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, ShowMinimap, 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, DisableAiSettings, 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.
 1308#[derive(Clone)]
 1309pub struct SelectionEffects {
 1310    nav_history: Option<bool>,
 1311    completions: bool,
 1312    scroll: Option<Autoscroll>,
 1313}
 1314
 1315impl Default for SelectionEffects {
 1316    fn default() -> Self {
 1317        Self {
 1318            nav_history: None,
 1319            completions: true,
 1320            scroll: Some(Autoscroll::fit()),
 1321        }
 1322    }
 1323}
 1324impl SelectionEffects {
 1325    pub fn scroll(scroll: Autoscroll) -> Self {
 1326        Self {
 1327            scroll: Some(scroll),
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn no_scroll() -> Self {
 1333        Self {
 1334            scroll: None,
 1335            ..Default::default()
 1336        }
 1337    }
 1338
 1339    pub fn completions(self, completions: bool) -> Self {
 1340        Self {
 1341            completions,
 1342            ..self
 1343        }
 1344    }
 1345
 1346    pub fn nav_history(self, nav_history: bool) -> Self {
 1347        Self {
 1348            nav_history: Some(nav_history),
 1349            ..self
 1350        }
 1351    }
 1352}
 1353
 1354struct DeferredSelectionEffectsState {
 1355    changed: bool,
 1356    effects: SelectionEffects,
 1357    old_cursor_position: Anchor,
 1358    history_entry: SelectionHistoryEntry,
 1359}
 1360
 1361#[derive(Default)]
 1362struct SelectionHistory {
 1363    #[allow(clippy::type_complexity)]
 1364    selections_by_transaction:
 1365        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1366    mode: SelectionHistoryMode,
 1367    undo_stack: VecDeque<SelectionHistoryEntry>,
 1368    redo_stack: VecDeque<SelectionHistoryEntry>,
 1369}
 1370
 1371impl SelectionHistory {
 1372    #[track_caller]
 1373    fn insert_transaction(
 1374        &mut self,
 1375        transaction_id: TransactionId,
 1376        selections: Arc<[Selection<Anchor>]>,
 1377    ) {
 1378        if selections.is_empty() {
 1379            log::error!(
 1380                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1381                std::panic::Location::caller()
 1382            );
 1383            return;
 1384        }
 1385        self.selections_by_transaction
 1386            .insert(transaction_id, (selections, None));
 1387    }
 1388
 1389    #[allow(clippy::type_complexity)]
 1390    fn transaction(
 1391        &self,
 1392        transaction_id: TransactionId,
 1393    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1394        self.selections_by_transaction.get(&transaction_id)
 1395    }
 1396
 1397    #[allow(clippy::type_complexity)]
 1398    fn transaction_mut(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1402        self.selections_by_transaction.get_mut(&transaction_id)
 1403    }
 1404
 1405    fn push(&mut self, entry: SelectionHistoryEntry) {
 1406        if !entry.selections.is_empty() {
 1407            match self.mode {
 1408                SelectionHistoryMode::Normal => {
 1409                    self.push_undo(entry);
 1410                    self.redo_stack.clear();
 1411                }
 1412                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1413                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1414                SelectionHistoryMode::Skipping => {}
 1415            }
 1416        }
 1417    }
 1418
 1419    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1420        if self
 1421            .undo_stack
 1422            .back()
 1423            .map_or(true, |e| e.selections != entry.selections)
 1424        {
 1425            self.undo_stack.push_back(entry);
 1426            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1427                self.undo_stack.pop_front();
 1428            }
 1429        }
 1430    }
 1431
 1432    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1433        if self
 1434            .redo_stack
 1435            .back()
 1436            .map_or(true, |e| e.selections != entry.selections)
 1437        {
 1438            self.redo_stack.push_back(entry);
 1439            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1440                self.redo_stack.pop_front();
 1441            }
 1442        }
 1443    }
 1444}
 1445
 1446#[derive(Clone, Copy)]
 1447pub struct RowHighlightOptions {
 1448    pub autoscroll: bool,
 1449    pub include_gutter: bool,
 1450}
 1451
 1452impl Default for RowHighlightOptions {
 1453    fn default() -> Self {
 1454        Self {
 1455            autoscroll: Default::default(),
 1456            include_gutter: true,
 1457        }
 1458    }
 1459}
 1460
 1461struct RowHighlight {
 1462    index: usize,
 1463    range: Range<Anchor>,
 1464    color: Hsla,
 1465    options: RowHighlightOptions,
 1466    type_id: TypeId,
 1467}
 1468
 1469#[derive(Clone, Debug)]
 1470struct AddSelectionsState {
 1471    groups: Vec<AddSelectionsGroup>,
 1472}
 1473
 1474#[derive(Clone, Debug)]
 1475struct AddSelectionsGroup {
 1476    above: bool,
 1477    stack: Vec<usize>,
 1478}
 1479
 1480#[derive(Clone)]
 1481struct SelectNextState {
 1482    query: AhoCorasick,
 1483    wordwise: bool,
 1484    done: bool,
 1485}
 1486
 1487impl std::fmt::Debug for SelectNextState {
 1488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1489        f.debug_struct(std::any::type_name::<Self>())
 1490            .field("wordwise", &self.wordwise)
 1491            .field("done", &self.done)
 1492            .finish()
 1493    }
 1494}
 1495
 1496#[derive(Debug)]
 1497struct AutocloseRegion {
 1498    selection_id: usize,
 1499    range: Range<Anchor>,
 1500    pair: BracketPair,
 1501}
 1502
 1503#[derive(Debug)]
 1504struct SnippetState {
 1505    ranges: Vec<Vec<Range<Anchor>>>,
 1506    active_index: usize,
 1507    choices: Vec<Option<Vec<String>>>,
 1508}
 1509
 1510#[doc(hidden)]
 1511pub struct RenameState {
 1512    pub range: Range<Anchor>,
 1513    pub old_name: Arc<str>,
 1514    pub editor: Entity<Editor>,
 1515    block_id: CustomBlockId,
 1516}
 1517
 1518struct InvalidationStack<T>(Vec<T>);
 1519
 1520struct RegisteredInlineCompletionProvider {
 1521    provider: Arc<dyn InlineCompletionProviderHandle>,
 1522    _subscription: Subscription,
 1523}
 1524
 1525#[derive(Debug, PartialEq, Eq)]
 1526pub struct ActiveDiagnosticGroup {
 1527    pub active_range: Range<Anchor>,
 1528    pub active_message: String,
 1529    pub group_id: usize,
 1530    pub blocks: HashSet<CustomBlockId>,
 1531}
 1532
 1533#[derive(Debug, PartialEq, Eq)]
 1534
 1535pub(crate) enum ActiveDiagnostic {
 1536    None,
 1537    All,
 1538    Group(ActiveDiagnosticGroup),
 1539}
 1540
 1541#[derive(Serialize, Deserialize, Clone, Debug)]
 1542pub struct ClipboardSelection {
 1543    /// The number of bytes in this selection.
 1544    pub len: usize,
 1545    /// Whether this was a full-line selection.
 1546    pub is_entire_line: bool,
 1547    /// The indentation of the first line when this content was originally copied.
 1548    pub first_line_indent: u32,
 1549}
 1550
 1551// selections, scroll behavior, was newest selection reversed
 1552type SelectSyntaxNodeHistoryState = (
 1553    Box<[Selection<usize>]>,
 1554    SelectSyntaxNodeScrollBehavior,
 1555    bool,
 1556);
 1557
 1558#[derive(Default)]
 1559struct SelectSyntaxNodeHistory {
 1560    stack: Vec<SelectSyntaxNodeHistoryState>,
 1561    // disable temporarily to allow changing selections without losing the stack
 1562    pub disable_clearing: bool,
 1563}
 1564
 1565impl SelectSyntaxNodeHistory {
 1566    pub fn try_clear(&mut self) {
 1567        if !self.disable_clearing {
 1568            self.stack.clear();
 1569        }
 1570    }
 1571
 1572    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1573        self.stack.push(selection);
 1574    }
 1575
 1576    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1577        self.stack.pop()
 1578    }
 1579}
 1580
 1581enum SelectSyntaxNodeScrollBehavior {
 1582    CursorTop,
 1583    FitSelection,
 1584    CursorBottom,
 1585}
 1586
 1587#[derive(Debug)]
 1588pub(crate) struct NavigationData {
 1589    cursor_anchor: Anchor,
 1590    cursor_position: Point,
 1591    scroll_anchor: ScrollAnchor,
 1592    scroll_top_row: u32,
 1593}
 1594
 1595#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1596pub enum GotoDefinitionKind {
 1597    Symbol,
 1598    Declaration,
 1599    Type,
 1600    Implementation,
 1601}
 1602
 1603#[derive(Debug, Clone)]
 1604enum InlayHintRefreshReason {
 1605    ModifiersChanged(bool),
 1606    Toggle(bool),
 1607    SettingsChange(InlayHintSettings),
 1608    NewLinesShown,
 1609    BufferEdited(HashSet<Arc<Language>>),
 1610    RefreshRequested,
 1611    ExcerptsRemoved(Vec<ExcerptId>),
 1612}
 1613
 1614impl InlayHintRefreshReason {
 1615    fn description(&self) -> &'static str {
 1616        match self {
 1617            Self::ModifiersChanged(_) => "modifiers changed",
 1618            Self::Toggle(_) => "toggle",
 1619            Self::SettingsChange(_) => "settings change",
 1620            Self::NewLinesShown => "new lines shown",
 1621            Self::BufferEdited(_) => "buffer edited",
 1622            Self::RefreshRequested => "refresh requested",
 1623            Self::ExcerptsRemoved(_) => "excerpts removed",
 1624        }
 1625    }
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    fn new_internal(
 1769        mode: EditorMode,
 1770        buffer: Entity<MultiBuffer>,
 1771        project: Option<Entity<Project>>,
 1772        display_map: Option<Entity<DisplayMap>>,
 1773        window: &mut Window,
 1774        cx: &mut Context<Self>,
 1775    ) -> Self {
 1776        debug_assert!(
 1777            display_map.is_none() || mode.is_minimap(),
 1778            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1779        );
 1780
 1781        let full_mode = mode.is_full();
 1782        let is_minimap = mode.is_minimap();
 1783        let diagnostics_max_severity = if full_mode {
 1784            EditorSettings::get_global(cx)
 1785                .diagnostics_max_severity
 1786                .unwrap_or(DiagnosticSeverity::Hint)
 1787        } else {
 1788            DiagnosticSeverity::Off
 1789        };
 1790        let style = window.text_style();
 1791        let font_size = style.font_size.to_pixels(window.rem_size());
 1792        let editor = cx.entity().downgrade();
 1793        let fold_placeholder = FoldPlaceholder {
 1794            constrain_width: true,
 1795            render: Arc::new(move |fold_id, fold_range, cx| {
 1796                let editor = editor.clone();
 1797                div()
 1798                    .id(fold_id)
 1799                    .bg(cx.theme().colors().ghost_element_background)
 1800                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1801                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1802                    .rounded_xs()
 1803                    .size_full()
 1804                    .cursor_pointer()
 1805                    .child("")
 1806                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1807                    .on_click(move |_, _window, cx| {
 1808                        editor
 1809                            .update(cx, |editor, cx| {
 1810                                editor.unfold_ranges(
 1811                                    &[fold_range.start..fold_range.end],
 1812                                    true,
 1813                                    false,
 1814                                    cx,
 1815                                );
 1816                                cx.stop_propagation();
 1817                            })
 1818                            .ok();
 1819                    })
 1820                    .into_any()
 1821            }),
 1822            merge_adjacent: true,
 1823            ..FoldPlaceholder::default()
 1824        };
 1825        let display_map = display_map.unwrap_or_else(|| {
 1826            cx.new(|cx| {
 1827                DisplayMap::new(
 1828                    buffer.clone(),
 1829                    style.font(),
 1830                    font_size,
 1831                    None,
 1832                    FILE_HEADER_HEIGHT,
 1833                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1834                    fold_placeholder,
 1835                    diagnostics_max_severity,
 1836                    cx,
 1837                )
 1838            })
 1839        });
 1840
 1841        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1842
 1843        let blink_manager = cx.new(|cx| {
 1844            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1845            if is_minimap {
 1846                blink_manager.disable(cx);
 1847            }
 1848            blink_manager
 1849        });
 1850
 1851        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1852            .then(|| language_settings::SoftWrap::None);
 1853
 1854        let mut project_subscriptions = Vec::new();
 1855        if full_mode {
 1856            if let Some(project) = project.as_ref() {
 1857                project_subscriptions.push(cx.subscribe_in(
 1858                    project,
 1859                    window,
 1860                    |editor, _, event, window, cx| match event {
 1861                        project::Event::RefreshCodeLens => {
 1862                            // we always query lens with actions, without storing them, always refreshing them
 1863                        }
 1864                        project::Event::RefreshInlayHints => {
 1865                            editor
 1866                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1867                        }
 1868                        project::Event::LanguageServerAdded(..)
 1869                        | project::Event::LanguageServerRemoved(..) => {
 1870                            if editor.tasks_update_task.is_none() {
 1871                                editor.tasks_update_task =
 1872                                    Some(editor.refresh_runnables(window, cx));
 1873                            }
 1874                            editor.update_lsp_data(true, None, window, cx);
 1875                        }
 1876                        project::Event::SnippetEdit(id, snippet_edits) => {
 1877                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                                let focus_handle = editor.focus_handle(cx);
 1879                                if focus_handle.is_focused(window) {
 1880                                    let snapshot = buffer.read(cx).snapshot();
 1881                                    for (range, snippet) in snippet_edits {
 1882                                        let editor_range =
 1883                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                        editor
 1885                                            .insert_snippet(
 1886                                                &[editor_range],
 1887                                                snippet.clone(),
 1888                                                window,
 1889                                                cx,
 1890                                            )
 1891                                            .ok();
 1892                                    }
 1893                                }
 1894                            }
 1895                        }
 1896                        _ => {}
 1897                    },
 1898                ));
 1899                if let Some(task_inventory) = project
 1900                    .read(cx)
 1901                    .task_store()
 1902                    .read(cx)
 1903                    .task_inventory()
 1904                    .cloned()
 1905                {
 1906                    project_subscriptions.push(cx.observe_in(
 1907                        &task_inventory,
 1908                        window,
 1909                        |editor, _, window, cx| {
 1910                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1911                        },
 1912                    ));
 1913                };
 1914
 1915                project_subscriptions.push(cx.subscribe_in(
 1916                    &project.read(cx).breakpoint_store(),
 1917                    window,
 1918                    |editor, _, event, window, cx| match event {
 1919                        BreakpointStoreEvent::ClearDebugLines => {
 1920                            editor.clear_row_highlights::<ActiveDebugLine>();
 1921                            editor.refresh_inline_values(cx);
 1922                        }
 1923                        BreakpointStoreEvent::SetDebugLine => {
 1924                            if editor.go_to_active_debug_line(window, cx) {
 1925                                cx.stop_propagation();
 1926                            }
 1927
 1928                            editor.refresh_inline_values(cx);
 1929                        }
 1930                        _ => {}
 1931                    },
 1932                ));
 1933                let git_store = project.read(cx).git_store().clone();
 1934                let project = project.clone();
 1935                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1936                    match event {
 1937                        GitStoreEvent::RepositoryUpdated(
 1938                            _,
 1939                            RepositoryEvent::Updated {
 1940                                new_instance: true, ..
 1941                            },
 1942                            _,
 1943                        ) => {
 1944                            this.load_diff_task = Some(
 1945                                update_uncommitted_diff_for_buffer(
 1946                                    cx.entity(),
 1947                                    &project,
 1948                                    this.buffer.read(cx).all_buffers(),
 1949                                    this.buffer.clone(),
 1950                                    cx,
 1951                                )
 1952                                .shared(),
 1953                            );
 1954                        }
 1955                        _ => {}
 1956                    }
 1957                }));
 1958            }
 1959        }
 1960
 1961        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1962
 1963        let inlay_hint_settings =
 1964            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1965        let focus_handle = cx.focus_handle();
 1966        if !is_minimap {
 1967            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1968                .detach();
 1969            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1970                .detach();
 1971            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1972                .detach();
 1973            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1974                .detach();
 1975            cx.observe_pending_input(window, Self::observe_pending_input)
 1976                .detach();
 1977        }
 1978
 1979        let show_indent_guides = if matches!(
 1980            mode,
 1981            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1982        ) {
 1983            Some(false)
 1984        } else {
 1985            None
 1986        };
 1987
 1988        let breakpoint_store = match (&mode, project.as_ref()) {
 1989            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1990            _ => None,
 1991        };
 1992
 1993        let mut code_action_providers = Vec::new();
 1994        let mut load_uncommitted_diff = None;
 1995        if let Some(project) = project.clone() {
 1996            load_uncommitted_diff = Some(
 1997                update_uncommitted_diff_for_buffer(
 1998                    cx.entity(),
 1999                    &project,
 2000                    buffer.read(cx).all_buffers(),
 2001                    buffer.clone(),
 2002                    cx,
 2003                )
 2004                .shared(),
 2005            );
 2006            code_action_providers.push(Rc::new(project) as Rc<_>);
 2007        }
 2008
 2009        let mut editor = Self {
 2010            focus_handle,
 2011            show_cursor_when_unfocused: false,
 2012            last_focused_descendant: None,
 2013            buffer: buffer.clone(),
 2014            display_map: display_map.clone(),
 2015            selections,
 2016            scroll_manager: ScrollManager::new(cx),
 2017            columnar_selection_state: None,
 2018            add_selections_state: None,
 2019            select_next_state: None,
 2020            select_prev_state: None,
 2021            selection_history: SelectionHistory::default(),
 2022            defer_selection_effects: false,
 2023            deferred_selection_effects_state: None,
 2024            autoclose_regions: Vec::new(),
 2025            snippet_stack: InvalidationStack::default(),
 2026            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2027            ime_transaction: None,
 2028            active_diagnostics: ActiveDiagnostic::None,
 2029            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2030            inline_diagnostics_update: Task::ready(()),
 2031            inline_diagnostics: Vec::new(),
 2032            soft_wrap_mode_override,
 2033            diagnostics_max_severity,
 2034            hard_wrap: None,
 2035            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2037            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2038            project,
 2039            blink_manager: blink_manager.clone(),
 2040            show_local_selections: true,
 2041            show_scrollbars: ScrollbarAxes {
 2042                horizontal: full_mode,
 2043                vertical: full_mode,
 2044            },
 2045            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2046            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2047            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2048            show_gutter: full_mode,
 2049            show_line_numbers: (!full_mode).then_some(false),
 2050            use_relative_line_numbers: None,
 2051            disable_expand_excerpt_buttons: !full_mode,
 2052            show_git_diff_gutter: None,
 2053            show_code_actions: None,
 2054            show_runnables: None,
 2055            show_breakpoints: None,
 2056            show_wrap_guides: None,
 2057            show_indent_guides,
 2058            placeholder_text: None,
 2059            highlight_order: 0,
 2060            highlighted_rows: HashMap::default(),
 2061            background_highlights: TreeMap::default(),
 2062            gutter_highlights: TreeMap::default(),
 2063            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2064            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2065            nav_history: None,
 2066            context_menu: RefCell::new(None),
 2067            context_menu_options: None,
 2068            mouse_context_menu: None,
 2069            completion_tasks: Vec::new(),
 2070            inline_blame_popover: None,
 2071            inline_blame_popover_show_task: None,
 2072            signature_help_state: SignatureHelpState::default(),
 2073            auto_signature_help: None,
 2074            find_all_references_task_sources: Vec::new(),
 2075            next_completion_id: 0,
 2076            next_inlay_id: 0,
 2077            code_action_providers,
 2078            available_code_actions: None,
 2079            code_actions_task: None,
 2080            quick_selection_highlight_task: None,
 2081            debounced_selection_highlight_task: None,
 2082            document_highlights_task: None,
 2083            linked_editing_range_task: None,
 2084            pending_rename: None,
 2085            searchable: !is_minimap,
 2086            cursor_shape: EditorSettings::get_global(cx)
 2087                .cursor_shape
 2088                .unwrap_or_default(),
 2089            current_line_highlight: None,
 2090            autoindent_mode: Some(AutoindentMode::EachLine),
 2091            collapse_matches: false,
 2092            workspace: None,
 2093            input_enabled: !is_minimap,
 2094            use_modal_editing: full_mode,
 2095            read_only: is_minimap,
 2096            use_autoclose: true,
 2097            use_auto_surround: true,
 2098            auto_replace_emoji_shortcode: false,
 2099            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2100            leader_id: None,
 2101            remote_id: None,
 2102            hover_state: HoverState::default(),
 2103            pending_mouse_down: None,
 2104            hovered_link_state: None,
 2105            edit_prediction_provider: None,
 2106            active_inline_completion: None,
 2107            stale_inline_completion_in_menu: None,
 2108            edit_prediction_preview: EditPredictionPreview::Inactive {
 2109                released_too_fast: false,
 2110            },
 2111            inline_diagnostics_enabled: full_mode,
 2112            diagnostics_enabled: full_mode,
 2113            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2114            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2115            gutter_hovered: false,
 2116            pixel_position_of_newest_cursor: None,
 2117            last_bounds: None,
 2118            last_position_map: None,
 2119            expect_bounds_change: None,
 2120            gutter_dimensions: GutterDimensions::default(),
 2121            style: None,
 2122            show_cursor_names: false,
 2123            hovered_cursors: HashMap::default(),
 2124            next_editor_action_id: EditorActionId::default(),
 2125            editor_actions: Rc::default(),
 2126            inline_completions_hidden_for_vim_mode: false,
 2127            show_inline_completions_override: None,
 2128            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2129            edit_prediction_settings: EditPredictionSettings::Disabled,
 2130            edit_prediction_indent_conflict: false,
 2131            edit_prediction_requires_modifier_in_indent_conflict: true,
 2132            custom_context_menu: None,
 2133            show_git_blame_gutter: false,
 2134            show_git_blame_inline: false,
 2135            show_selection_menu: None,
 2136            show_git_blame_inline_delay_task: None,
 2137            git_blame_inline_enabled: full_mode
 2138                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2139            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2140            serialize_dirty_buffers: !is_minimap
 2141                && ProjectSettings::get_global(cx)
 2142                    .session
 2143                    .restore_unsaved_buffers,
 2144            blame: None,
 2145            blame_subscription: None,
 2146            tasks: BTreeMap::default(),
 2147
 2148            breakpoint_store,
 2149            gutter_breakpoint_indicator: (None, None),
 2150            hovered_diff_hunk_row: None,
 2151            _subscriptions: (!is_minimap)
 2152                .then(|| {
 2153                    vec![
 2154                        cx.observe(&buffer, Self::on_buffer_changed),
 2155                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2156                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2157                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2158                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2159                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2160                        cx.observe_window_activation(window, |editor, window, cx| {
 2161                            let active = window.is_window_active();
 2162                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2163                                if active {
 2164                                    blink_manager.enable(cx);
 2165                                } else {
 2166                                    blink_manager.disable(cx);
 2167                                }
 2168                            });
 2169                            if active {
 2170                                editor.show_mouse_cursor(cx);
 2171                            }
 2172                        }),
 2173                    ]
 2174                })
 2175                .unwrap_or_default(),
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206
 2207        if is_minimap {
 2208            return editor;
 2209        }
 2210
 2211        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2212            editor
 2213                ._subscriptions
 2214                .push(cx.observe(breakpoints, |_, _, cx| {
 2215                    cx.notify();
 2216                }));
 2217        }
 2218        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2219        editor._subscriptions.extend(project_subscriptions);
 2220
 2221        editor._subscriptions.push(cx.subscribe_in(
 2222            &cx.entity(),
 2223            window,
 2224            |editor, _, e: &EditorEvent, window, cx| match e {
 2225                EditorEvent::ScrollPositionChanged { local, .. } => {
 2226                    if *local {
 2227                        let new_anchor = editor.scroll_manager.anchor();
 2228                        let snapshot = editor.snapshot(window, cx);
 2229                        editor.update_restoration_data(cx, move |data| {
 2230                            data.scroll_position = (
 2231                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2232                                new_anchor.offset,
 2233                            );
 2234                        });
 2235                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2236                        editor.inline_blame_popover.take();
 2237                    }
 2238                }
 2239                EditorEvent::Edited { .. } => {
 2240                    if !vim_enabled(cx) {
 2241                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2242                        let pop_state = editor
 2243                            .change_list
 2244                            .last()
 2245                            .map(|previous| {
 2246                                previous.len() == selections.len()
 2247                                    && previous.iter().enumerate().all(|(ix, p)| {
 2248                                        p.to_display_point(&map).row()
 2249                                            == selections[ix].head().row()
 2250                                    })
 2251                            })
 2252                            .unwrap_or(false);
 2253                        let new_positions = selections
 2254                            .into_iter()
 2255                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2256                            .collect();
 2257                        editor
 2258                            .change_list
 2259                            .push_to_change_list(pop_state, new_positions);
 2260                    }
 2261                }
 2262                _ => (),
 2263            },
 2264        ));
 2265
 2266        if let Some(dap_store) = editor
 2267            .project
 2268            .as_ref()
 2269            .map(|project| project.read(cx).dap_store())
 2270        {
 2271            let weak_editor = cx.weak_entity();
 2272
 2273            editor
 2274                ._subscriptions
 2275                .push(
 2276                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2277                        let session_entity = cx.entity();
 2278                        weak_editor
 2279                            .update(cx, |editor, cx| {
 2280                                editor._subscriptions.push(
 2281                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2282                                );
 2283                            })
 2284                            .ok();
 2285                    }),
 2286                );
 2287
 2288            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2289                editor
 2290                    ._subscriptions
 2291                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2292            }
 2293        }
 2294
 2295        // skip adding the initial selection to selection history
 2296        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2297        editor.end_selection(window, cx);
 2298        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2299
 2300        editor.scroll_manager.show_scrollbars(window, cx);
 2301        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2302
 2303        if full_mode {
 2304            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2305            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2306
 2307            if editor.git_blame_inline_enabled {
 2308                editor.start_git_blame_inline(false, window, cx);
 2309            }
 2310
 2311            editor.go_to_active_debug_line(window, cx);
 2312
 2313            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2314                if let Some(project) = editor.project.as_ref() {
 2315                    let handle = project.update(cx, |project, cx| {
 2316                        project.register_buffer_with_language_servers(&buffer, cx)
 2317                    });
 2318                    editor
 2319                        .registered_buffers
 2320                        .insert(buffer.read(cx).remote_id(), handle);
 2321                }
 2322            }
 2323
 2324            editor.minimap =
 2325                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2326            editor.colors = Some(LspColorData::new(cx));
 2327            editor.update_lsp_data(false, None, window, cx);
 2328        }
 2329
 2330        if editor.mode.is_full() {
 2331            editor.report_editor_event("Editor Opened", None, cx);
 2332        }
 2333
 2334        editor
 2335    }
 2336
 2337    pub fn deploy_mouse_context_menu(
 2338        &mut self,
 2339        position: gpui::Point<Pixels>,
 2340        context_menu: Entity<ContextMenu>,
 2341        window: &mut Window,
 2342        cx: &mut Context<Self>,
 2343    ) {
 2344        self.mouse_context_menu = Some(MouseContextMenu::new(
 2345            self,
 2346            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2347            context_menu,
 2348            window,
 2349            cx,
 2350        ));
 2351    }
 2352
 2353    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2354        self.mouse_context_menu
 2355            .as_ref()
 2356            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2357    }
 2358
 2359    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2360        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2361    }
 2362
 2363    fn key_context_internal(
 2364        &self,
 2365        has_active_edit_prediction: bool,
 2366        window: &Window,
 2367        cx: &App,
 2368    ) -> KeyContext {
 2369        let mut key_context = KeyContext::new_with_defaults();
 2370        key_context.add("Editor");
 2371        let mode = match self.mode {
 2372            EditorMode::SingleLine { .. } => "single_line",
 2373            EditorMode::AutoHeight { .. } => "auto_height",
 2374            EditorMode::Minimap { .. } => "minimap",
 2375            EditorMode::Full { .. } => "full",
 2376        };
 2377
 2378        if EditorSettings::jupyter_enabled(cx) {
 2379            key_context.add("jupyter");
 2380        }
 2381
 2382        key_context.set("mode", mode);
 2383        if self.pending_rename.is_some() {
 2384            key_context.add("renaming");
 2385        }
 2386
 2387        match self.context_menu.borrow().as_ref() {
 2388            Some(CodeContextMenu::Completions(menu)) => {
 2389                if menu.visible() {
 2390                    key_context.add("menu");
 2391                    key_context.add("showing_completions");
 2392                }
 2393            }
 2394            Some(CodeContextMenu::CodeActions(menu)) => {
 2395                if menu.visible() {
 2396                    key_context.add("menu");
 2397                    key_context.add("showing_code_actions")
 2398                }
 2399            }
 2400            None => {}
 2401        }
 2402
 2403        if self.signature_help_state.has_multiple_signatures() {
 2404            key_context.add("showing_signature_help");
 2405        }
 2406
 2407        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2408        if !self.focus_handle(cx).contains_focused(window, cx)
 2409            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2410        {
 2411            for addon in self.addons.values() {
 2412                addon.extend_key_context(&mut key_context, cx)
 2413            }
 2414        }
 2415
 2416        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2417            if let Some(extension) = singleton_buffer
 2418                .read(cx)
 2419                .file()
 2420                .and_then(|file| file.path().extension()?.to_str())
 2421            {
 2422                key_context.set("extension", extension.to_string());
 2423            }
 2424        } else {
 2425            key_context.add("multibuffer");
 2426        }
 2427
 2428        if has_active_edit_prediction {
 2429            if self.edit_prediction_in_conflict() {
 2430                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2431            } else {
 2432                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2433                key_context.add("copilot_suggestion");
 2434            }
 2435        }
 2436
 2437        if self.selection_mark_mode {
 2438            key_context.add("selection_mode");
 2439        }
 2440
 2441        key_context
 2442    }
 2443
 2444    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2445        if self.mouse_cursor_hidden {
 2446            self.mouse_cursor_hidden = false;
 2447            cx.notify();
 2448        }
 2449    }
 2450
 2451    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2452        let hide_mouse_cursor = match origin {
 2453            HideMouseCursorOrigin::TypingAction => {
 2454                matches!(
 2455                    self.hide_mouse_mode,
 2456                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2457                )
 2458            }
 2459            HideMouseCursorOrigin::MovementAction => {
 2460                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2461            }
 2462        };
 2463        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2464            self.mouse_cursor_hidden = hide_mouse_cursor;
 2465            cx.notify();
 2466        }
 2467    }
 2468
 2469    pub fn edit_prediction_in_conflict(&self) -> bool {
 2470        if !self.show_edit_predictions_in_menu() {
 2471            return false;
 2472        }
 2473
 2474        let showing_completions = self
 2475            .context_menu
 2476            .borrow()
 2477            .as_ref()
 2478            .map_or(false, |context| {
 2479                matches!(context, CodeContextMenu::Completions(_))
 2480            });
 2481
 2482        showing_completions
 2483            || self.edit_prediction_requires_modifier()
 2484            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2485            // bindings to insert tab characters.
 2486            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2487    }
 2488
 2489    pub fn accept_edit_prediction_keybind(
 2490        &self,
 2491        accept_partial: bool,
 2492        window: &Window,
 2493        cx: &App,
 2494    ) -> AcceptEditPredictionBinding {
 2495        let key_context = self.key_context_internal(true, window, cx);
 2496        let in_conflict = self.edit_prediction_in_conflict();
 2497
 2498        let bindings = if accept_partial {
 2499            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2500        } else {
 2501            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2502        };
 2503
 2504        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2505        // just the first one.
 2506        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2507            !in_conflict
 2508                || binding
 2509                    .keystrokes()
 2510                    .first()
 2511                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2512        }))
 2513    }
 2514
 2515    pub fn new_file(
 2516        workspace: &mut Workspace,
 2517        _: &workspace::NewFile,
 2518        window: &mut Window,
 2519        cx: &mut Context<Workspace>,
 2520    ) {
 2521        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2522            "Failed to create buffer",
 2523            window,
 2524            cx,
 2525            |e, _, _| match e.error_code() {
 2526                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2527                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2528                e.error_tag("required").unwrap_or("the latest version")
 2529            )),
 2530                _ => None,
 2531            },
 2532        );
 2533    }
 2534
 2535    pub fn new_in_workspace(
 2536        workspace: &mut Workspace,
 2537        window: &mut Window,
 2538        cx: &mut Context<Workspace>,
 2539    ) -> Task<Result<Entity<Editor>>> {
 2540        let project = workspace.project().clone();
 2541        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2542
 2543        cx.spawn_in(window, async move |workspace, cx| {
 2544            let buffer = create.await?;
 2545            workspace.update_in(cx, |workspace, window, cx| {
 2546                let editor =
 2547                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2548                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2549                editor
 2550            })
 2551        })
 2552    }
 2553
 2554    fn new_file_vertical(
 2555        workspace: &mut Workspace,
 2556        _: &workspace::NewFileSplitVertical,
 2557        window: &mut Window,
 2558        cx: &mut Context<Workspace>,
 2559    ) {
 2560        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2561    }
 2562
 2563    fn new_file_horizontal(
 2564        workspace: &mut Workspace,
 2565        _: &workspace::NewFileSplitHorizontal,
 2566        window: &mut Window,
 2567        cx: &mut Context<Workspace>,
 2568    ) {
 2569        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2570    }
 2571
 2572    fn new_file_in_direction(
 2573        workspace: &mut Workspace,
 2574        direction: SplitDirection,
 2575        window: &mut Window,
 2576        cx: &mut Context<Workspace>,
 2577    ) {
 2578        let project = workspace.project().clone();
 2579        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2580
 2581        cx.spawn_in(window, async move |workspace, cx| {
 2582            let buffer = create.await?;
 2583            workspace.update_in(cx, move |workspace, window, cx| {
 2584                workspace.split_item(
 2585                    direction,
 2586                    Box::new(
 2587                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2588                    ),
 2589                    window,
 2590                    cx,
 2591                )
 2592            })?;
 2593            anyhow::Ok(())
 2594        })
 2595        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2596            match e.error_code() {
 2597                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2598                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2599                e.error_tag("required").unwrap_or("the latest version")
 2600            )),
 2601                _ => None,
 2602            }
 2603        });
 2604    }
 2605
 2606    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2607        self.leader_id
 2608    }
 2609
 2610    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2611        &self.buffer
 2612    }
 2613
 2614    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2615        self.workspace.as_ref()?.0.upgrade()
 2616    }
 2617
 2618    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2619        self.buffer().read(cx).title(cx)
 2620    }
 2621
 2622    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2623        let git_blame_gutter_max_author_length = self
 2624            .render_git_blame_gutter(cx)
 2625            .then(|| {
 2626                if let Some(blame) = self.blame.as_ref() {
 2627                    let max_author_length =
 2628                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2629                    Some(max_author_length)
 2630                } else {
 2631                    None
 2632                }
 2633            })
 2634            .flatten();
 2635
 2636        EditorSnapshot {
 2637            mode: self.mode.clone(),
 2638            show_gutter: self.show_gutter,
 2639            show_line_numbers: self.show_line_numbers,
 2640            show_git_diff_gutter: self.show_git_diff_gutter,
 2641            show_code_actions: self.show_code_actions,
 2642            show_runnables: self.show_runnables,
 2643            show_breakpoints: self.show_breakpoints,
 2644            git_blame_gutter_max_author_length,
 2645            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2646            scroll_anchor: self.scroll_manager.anchor(),
 2647            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2648            placeholder_text: self.placeholder_text.clone(),
 2649            is_focused: self.focus_handle.is_focused(window),
 2650            current_line_highlight: self
 2651                .current_line_highlight
 2652                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2653            gutter_hovered: self.gutter_hovered,
 2654        }
 2655    }
 2656
 2657    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2658        self.buffer.read(cx).language_at(point, cx)
 2659    }
 2660
 2661    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2662        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2663    }
 2664
 2665    pub fn active_excerpt(
 2666        &self,
 2667        cx: &App,
 2668    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2669        self.buffer
 2670            .read(cx)
 2671            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2672    }
 2673
 2674    pub fn mode(&self) -> &EditorMode {
 2675        &self.mode
 2676    }
 2677
 2678    pub fn set_mode(&mut self, mode: EditorMode) {
 2679        self.mode = mode;
 2680    }
 2681
 2682    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2683        self.collaboration_hub.as_deref()
 2684    }
 2685
 2686    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2687        self.collaboration_hub = Some(hub);
 2688    }
 2689
 2690    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2691        self.in_project_search = in_project_search;
 2692    }
 2693
 2694    pub fn set_custom_context_menu(
 2695        &mut self,
 2696        f: impl 'static
 2697        + Fn(
 2698            &mut Self,
 2699            DisplayPoint,
 2700            &mut Window,
 2701            &mut Context<Self>,
 2702        ) -> Option<Entity<ui::ContextMenu>>,
 2703    ) {
 2704        self.custom_context_menu = Some(Box::new(f))
 2705    }
 2706
 2707    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2708        self.completion_provider = provider;
 2709    }
 2710
 2711    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2712        self.semantics_provider.clone()
 2713    }
 2714
 2715    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2716        self.semantics_provider = provider;
 2717    }
 2718
 2719    pub fn set_edit_prediction_provider<T>(
 2720        &mut self,
 2721        provider: Option<Entity<T>>,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) where
 2725        T: EditPredictionProvider,
 2726    {
 2727        self.edit_prediction_provider =
 2728            provider.map(|provider| RegisteredInlineCompletionProvider {
 2729                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2730                    if this.focus_handle.is_focused(window) {
 2731                        this.update_visible_inline_completion(window, cx);
 2732                    }
 2733                }),
 2734                provider: Arc::new(provider),
 2735            });
 2736        self.update_edit_prediction_settings(cx);
 2737        self.refresh_inline_completion(false, false, window, cx);
 2738    }
 2739
 2740    pub fn placeholder_text(&self) -> Option<&str> {
 2741        self.placeholder_text.as_deref()
 2742    }
 2743
 2744    pub fn set_placeholder_text(
 2745        &mut self,
 2746        placeholder_text: impl Into<Arc<str>>,
 2747        cx: &mut Context<Self>,
 2748    ) {
 2749        let placeholder_text = Some(placeholder_text.into());
 2750        if self.placeholder_text != placeholder_text {
 2751            self.placeholder_text = placeholder_text;
 2752            cx.notify();
 2753        }
 2754    }
 2755
 2756    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2757        self.cursor_shape = cursor_shape;
 2758
 2759        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2760        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2761
 2762        cx.notify();
 2763    }
 2764
 2765    pub fn set_current_line_highlight(
 2766        &mut self,
 2767        current_line_highlight: Option<CurrentLineHighlight>,
 2768    ) {
 2769        self.current_line_highlight = current_line_highlight;
 2770    }
 2771
 2772    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2773        self.collapse_matches = collapse_matches;
 2774    }
 2775
 2776    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2777        let buffers = self.buffer.read(cx).all_buffers();
 2778        let Some(project) = self.project.as_ref() else {
 2779            return;
 2780        };
 2781        project.update(cx, |project, cx| {
 2782            for buffer in buffers {
 2783                self.registered_buffers
 2784                    .entry(buffer.read(cx).remote_id())
 2785                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2786            }
 2787        })
 2788    }
 2789
 2790    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2791        if self.collapse_matches {
 2792            return range.start..range.start;
 2793        }
 2794        range.clone()
 2795    }
 2796
 2797    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2798        if self.display_map.read(cx).clip_at_line_ends != clip {
 2799            self.display_map
 2800                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2801        }
 2802    }
 2803
 2804    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2805        self.input_enabled = input_enabled;
 2806    }
 2807
 2808    pub fn set_inline_completions_hidden_for_vim_mode(
 2809        &mut self,
 2810        hidden: bool,
 2811        window: &mut Window,
 2812        cx: &mut Context<Self>,
 2813    ) {
 2814        if hidden != self.inline_completions_hidden_for_vim_mode {
 2815            self.inline_completions_hidden_for_vim_mode = hidden;
 2816            if hidden {
 2817                self.update_visible_inline_completion(window, cx);
 2818            } else {
 2819                self.refresh_inline_completion(true, false, window, cx);
 2820            }
 2821        }
 2822    }
 2823
 2824    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2825        self.menu_inline_completions_policy = value;
 2826    }
 2827
 2828    pub fn set_autoindent(&mut self, autoindent: bool) {
 2829        if autoindent {
 2830            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2831        } else {
 2832            self.autoindent_mode = None;
 2833        }
 2834    }
 2835
 2836    pub fn read_only(&self, cx: &App) -> bool {
 2837        self.read_only || self.buffer.read(cx).read_only()
 2838    }
 2839
 2840    pub fn set_read_only(&mut self, read_only: bool) {
 2841        self.read_only = read_only;
 2842    }
 2843
 2844    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2845        self.use_autoclose = autoclose;
 2846    }
 2847
 2848    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2849        self.use_auto_surround = auto_surround;
 2850    }
 2851
 2852    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2853        self.auto_replace_emoji_shortcode = auto_replace;
 2854    }
 2855
 2856    pub fn toggle_edit_predictions(
 2857        &mut self,
 2858        _: &ToggleEditPrediction,
 2859        window: &mut Window,
 2860        cx: &mut Context<Self>,
 2861    ) {
 2862        if self.show_inline_completions_override.is_some() {
 2863            self.set_show_edit_predictions(None, window, cx);
 2864        } else {
 2865            let show_edit_predictions = !self.edit_predictions_enabled();
 2866            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2867        }
 2868    }
 2869
 2870    pub fn set_show_edit_predictions(
 2871        &mut self,
 2872        show_edit_predictions: Option<bool>,
 2873        window: &mut Window,
 2874        cx: &mut Context<Self>,
 2875    ) {
 2876        self.show_inline_completions_override = show_edit_predictions;
 2877        self.update_edit_prediction_settings(cx);
 2878
 2879        if let Some(false) = show_edit_predictions {
 2880            self.discard_inline_completion(false, cx);
 2881        } else {
 2882            self.refresh_inline_completion(false, true, window, cx);
 2883        }
 2884    }
 2885
 2886    fn inline_completions_disabled_in_scope(
 2887        &self,
 2888        buffer: &Entity<Buffer>,
 2889        buffer_position: language::Anchor,
 2890        cx: &App,
 2891    ) -> bool {
 2892        let snapshot = buffer.read(cx).snapshot();
 2893        let settings = snapshot.settings_at(buffer_position, cx);
 2894
 2895        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2896            return false;
 2897        };
 2898
 2899        scope.override_name().map_or(false, |scope_name| {
 2900            settings
 2901                .edit_predictions_disabled_in
 2902                .iter()
 2903                .any(|s| s == scope_name)
 2904        })
 2905    }
 2906
 2907    pub fn set_use_modal_editing(&mut self, to: bool) {
 2908        self.use_modal_editing = to;
 2909    }
 2910
 2911    pub fn use_modal_editing(&self) -> bool {
 2912        self.use_modal_editing
 2913    }
 2914
 2915    fn selections_did_change(
 2916        &mut self,
 2917        local: bool,
 2918        old_cursor_position: &Anchor,
 2919        effects: SelectionEffects,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        window.invalidate_character_coordinates();
 2924
 2925        // Copy selections to primary selection buffer
 2926        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2927        if local {
 2928            let selections = self.selections.all::<usize>(cx);
 2929            let buffer_handle = self.buffer.read(cx).read(cx);
 2930
 2931            let mut text = String::new();
 2932            for (index, selection) in selections.iter().enumerate() {
 2933                let text_for_selection = buffer_handle
 2934                    .text_for_range(selection.start..selection.end)
 2935                    .collect::<String>();
 2936
 2937                text.push_str(&text_for_selection);
 2938                if index != selections.len() - 1 {
 2939                    text.push('\n');
 2940                }
 2941            }
 2942
 2943            if !text.is_empty() {
 2944                cx.write_to_primary(ClipboardItem::new_string(text));
 2945            }
 2946        }
 2947
 2948        let selection_anchors = self.selections.disjoint_anchors();
 2949
 2950        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2951            self.buffer.update(cx, |buffer, cx| {
 2952                buffer.set_active_selections(
 2953                    &selection_anchors,
 2954                    self.selections.line_mode,
 2955                    self.cursor_shape,
 2956                    cx,
 2957                )
 2958            });
 2959        }
 2960        let display_map = self
 2961            .display_map
 2962            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2963        let buffer = &display_map.buffer_snapshot;
 2964        if self.selections.count() == 1 {
 2965            self.add_selections_state = None;
 2966        }
 2967        self.select_next_state = None;
 2968        self.select_prev_state = None;
 2969        self.select_syntax_node_history.try_clear();
 2970        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2971        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2972        self.take_rename(false, window, cx);
 2973
 2974        let newest_selection = self.selections.newest_anchor();
 2975        let new_cursor_position = newest_selection.head();
 2976        let selection_start = newest_selection.start;
 2977
 2978        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2979            self.push_to_nav_history(
 2980                *old_cursor_position,
 2981                Some(new_cursor_position.to_point(buffer)),
 2982                false,
 2983                effects.nav_history == Some(true),
 2984                cx,
 2985            );
 2986        }
 2987
 2988        if local {
 2989            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2990                if !self.registered_buffers.contains_key(&buffer_id) {
 2991                    if let Some(project) = self.project.as_ref() {
 2992                        project.update(cx, |project, cx| {
 2993                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2994                                return;
 2995                            };
 2996                            self.registered_buffers.insert(
 2997                                buffer_id,
 2998                                project.register_buffer_with_language_servers(&buffer, cx),
 2999                            );
 3000                        })
 3001                    }
 3002                }
 3003            }
 3004
 3005            let mut context_menu = self.context_menu.borrow_mut();
 3006            let completion_menu = match context_menu.as_ref() {
 3007                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3008                Some(CodeContextMenu::CodeActions(_)) => {
 3009                    *context_menu = None;
 3010                    None
 3011                }
 3012                None => None,
 3013            };
 3014            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3015            drop(context_menu);
 3016
 3017            if effects.completions {
 3018                if let Some(completion_position) = completion_position {
 3019                    let start_offset = selection_start.to_offset(buffer);
 3020                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3021                    let continue_showing = if position_matches {
 3022                        if self.snippet_stack.is_empty() {
 3023                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3024                        } else {
 3025                            // Snippet choices can be shown even when the cursor is in whitespace.
 3026                            // Dismissing the menu with actions like backspace is handled by
 3027                            // invalidation regions.
 3028                            true
 3029                        }
 3030                    } else {
 3031                        false
 3032                    };
 3033
 3034                    if continue_showing {
 3035                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3036                    } else {
 3037                        self.hide_context_menu(window, cx);
 3038                    }
 3039                }
 3040            }
 3041
 3042            hide_hover(self, cx);
 3043
 3044            if old_cursor_position.to_display_point(&display_map).row()
 3045                != new_cursor_position.to_display_point(&display_map).row()
 3046            {
 3047                self.available_code_actions.take();
 3048            }
 3049            self.refresh_code_actions(window, cx);
 3050            self.refresh_document_highlights(cx);
 3051            self.refresh_selected_text_highlights(false, window, cx);
 3052            refresh_matching_bracket_highlights(self, window, cx);
 3053            self.update_visible_inline_completion(window, cx);
 3054            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3055            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3056            self.inline_blame_popover.take();
 3057            if self.git_blame_inline_enabled {
 3058                self.start_inline_blame_timer(window, cx);
 3059            }
 3060        }
 3061
 3062        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3063        cx.emit(EditorEvent::SelectionsChanged { local });
 3064
 3065        let selections = &self.selections.disjoint;
 3066        if selections.len() == 1 {
 3067            cx.emit(SearchEvent::ActiveMatchChanged)
 3068        }
 3069        if local {
 3070            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3071                let inmemory_selections = selections
 3072                    .iter()
 3073                    .map(|s| {
 3074                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3075                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3076                    })
 3077                    .collect();
 3078                self.update_restoration_data(cx, |data| {
 3079                    data.selections = inmemory_selections;
 3080                });
 3081
 3082                if WorkspaceSettings::get(None, cx).restore_on_startup
 3083                    != RestoreOnStartupBehavior::None
 3084                {
 3085                    if let Some(workspace_id) =
 3086                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3087                    {
 3088                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3089                        let selections = selections.clone();
 3090                        let background_executor = cx.background_executor().clone();
 3091                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3092                        self.serialize_selections = cx.background_spawn(async move {
 3093                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3094                            let db_selections = selections
 3095                                .iter()
 3096                                .map(|selection| {
 3097                                    (
 3098                                        selection.start.to_offset(&snapshot),
 3099                                        selection.end.to_offset(&snapshot),
 3100                                    )
 3101                                })
 3102                                .collect();
 3103
 3104                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3105                                .await
 3106                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3107                                .log_err();
 3108                        });
 3109                    }
 3110                }
 3111            }
 3112        }
 3113
 3114        cx.notify();
 3115    }
 3116
 3117    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3118        use text::ToOffset as _;
 3119        use text::ToPoint as _;
 3120
 3121        if self.mode.is_minimap()
 3122            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3123        {
 3124            return;
 3125        }
 3126
 3127        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3128            return;
 3129        };
 3130
 3131        let snapshot = singleton.read(cx).snapshot();
 3132        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3133            let display_snapshot = display_map.snapshot(cx);
 3134
 3135            display_snapshot
 3136                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3137                .map(|fold| {
 3138                    fold.range.start.text_anchor.to_point(&snapshot)
 3139                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3140                })
 3141                .collect()
 3142        });
 3143        self.update_restoration_data(cx, |data| {
 3144            data.folds = inmemory_folds;
 3145        });
 3146
 3147        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3148            return;
 3149        };
 3150        let background_executor = cx.background_executor().clone();
 3151        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3152        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3153            display_map
 3154                .snapshot(cx)
 3155                .folds_in_range(0..snapshot.len())
 3156                .map(|fold| {
 3157                    (
 3158                        fold.range.start.text_anchor.to_offset(&snapshot),
 3159                        fold.range.end.text_anchor.to_offset(&snapshot),
 3160                    )
 3161                })
 3162                .collect()
 3163        });
 3164        self.serialize_folds = cx.background_spawn(async move {
 3165            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3166            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3167                .await
 3168                .with_context(|| {
 3169                    format!(
 3170                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3171                    )
 3172                })
 3173                .log_err();
 3174        });
 3175    }
 3176
 3177    pub fn sync_selections(
 3178        &mut self,
 3179        other: Entity<Editor>,
 3180        cx: &mut Context<Self>,
 3181    ) -> gpui::Subscription {
 3182        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3183        self.selections.change_with(cx, |selections| {
 3184            selections.select_anchors(other_selections);
 3185        });
 3186
 3187        let other_subscription =
 3188            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3189                EditorEvent::SelectionsChanged { local: true } => {
 3190                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3191                    if other_selections.is_empty() {
 3192                        return;
 3193                    }
 3194                    this.selections.change_with(cx, |selections| {
 3195                        selections.select_anchors(other_selections);
 3196                    });
 3197                }
 3198                _ => {}
 3199            });
 3200
 3201        let this_subscription =
 3202            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3203                EditorEvent::SelectionsChanged { local: true } => {
 3204                    let these_selections = this.selections.disjoint.to_vec();
 3205                    if these_selections.is_empty() {
 3206                        return;
 3207                    }
 3208                    other.update(cx, |other_editor, cx| {
 3209                        other_editor.selections.change_with(cx, |selections| {
 3210                            selections.select_anchors(these_selections);
 3211                        })
 3212                    });
 3213                }
 3214                _ => {}
 3215            });
 3216
 3217        Subscription::join(other_subscription, this_subscription)
 3218    }
 3219
 3220    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3221    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3222    /// effects of selection change occur at the end of the transaction.
 3223    pub fn change_selections<R>(
 3224        &mut self,
 3225        effects: SelectionEffects,
 3226        window: &mut Window,
 3227        cx: &mut Context<Self>,
 3228        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3229    ) -> R {
 3230        if let Some(state) = &mut self.deferred_selection_effects_state {
 3231            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3232            state.effects.completions = effects.completions;
 3233            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3234            let (changed, result) = self.selections.change_with(cx, change);
 3235            state.changed |= changed;
 3236            return result;
 3237        }
 3238        let mut state = DeferredSelectionEffectsState {
 3239            changed: false,
 3240            effects,
 3241            old_cursor_position: self.selections.newest_anchor().head(),
 3242            history_entry: SelectionHistoryEntry {
 3243                selections: self.selections.disjoint_anchors(),
 3244                select_next_state: self.select_next_state.clone(),
 3245                select_prev_state: self.select_prev_state.clone(),
 3246                add_selections_state: self.add_selections_state.clone(),
 3247            },
 3248        };
 3249        let (changed, result) = self.selections.change_with(cx, change);
 3250        state.changed = state.changed || changed;
 3251        if self.defer_selection_effects {
 3252            self.deferred_selection_effects_state = Some(state);
 3253        } else {
 3254            self.apply_selection_effects(state, window, cx);
 3255        }
 3256        result
 3257    }
 3258
 3259    /// Defers the effects of selection change, so that the effects of multiple calls to
 3260    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3261    /// to selection history and the state of popovers based on selection position aren't
 3262    /// erroneously updated.
 3263    pub fn with_selection_effects_deferred<R>(
 3264        &mut self,
 3265        window: &mut Window,
 3266        cx: &mut Context<Self>,
 3267        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3268    ) -> R {
 3269        let already_deferred = self.defer_selection_effects;
 3270        self.defer_selection_effects = true;
 3271        let result = update(self, window, cx);
 3272        if !already_deferred {
 3273            self.defer_selection_effects = false;
 3274            if let Some(state) = self.deferred_selection_effects_state.take() {
 3275                self.apply_selection_effects(state, window, cx);
 3276            }
 3277        }
 3278        result
 3279    }
 3280
 3281    fn apply_selection_effects(
 3282        &mut self,
 3283        state: DeferredSelectionEffectsState,
 3284        window: &mut Window,
 3285        cx: &mut Context<Self>,
 3286    ) {
 3287        if state.changed {
 3288            self.selection_history.push(state.history_entry);
 3289
 3290            if let Some(autoscroll) = state.effects.scroll {
 3291                self.request_autoscroll(autoscroll, cx);
 3292            }
 3293
 3294            let old_cursor_position = &state.old_cursor_position;
 3295
 3296            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3297
 3298            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3299                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3300            }
 3301        }
 3302    }
 3303
 3304    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3305    where
 3306        I: IntoIterator<Item = (Range<S>, T)>,
 3307        S: ToOffset,
 3308        T: Into<Arc<str>>,
 3309    {
 3310        if self.read_only(cx) {
 3311            return;
 3312        }
 3313
 3314        self.buffer
 3315            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3316    }
 3317
 3318    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3319    where
 3320        I: IntoIterator<Item = (Range<S>, T)>,
 3321        S: ToOffset,
 3322        T: Into<Arc<str>>,
 3323    {
 3324        if self.read_only(cx) {
 3325            return;
 3326        }
 3327
 3328        self.buffer.update(cx, |buffer, cx| {
 3329            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3330        });
 3331    }
 3332
 3333    pub fn edit_with_block_indent<I, S, T>(
 3334        &mut self,
 3335        edits: I,
 3336        original_indent_columns: Vec<Option<u32>>,
 3337        cx: &mut Context<Self>,
 3338    ) where
 3339        I: IntoIterator<Item = (Range<S>, T)>,
 3340        S: ToOffset,
 3341        T: Into<Arc<str>>,
 3342    {
 3343        if self.read_only(cx) {
 3344            return;
 3345        }
 3346
 3347        self.buffer.update(cx, |buffer, cx| {
 3348            buffer.edit(
 3349                edits,
 3350                Some(AutoindentMode::Block {
 3351                    original_indent_columns,
 3352                }),
 3353                cx,
 3354            )
 3355        });
 3356    }
 3357
 3358    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3359        self.hide_context_menu(window, cx);
 3360
 3361        match phase {
 3362            SelectPhase::Begin {
 3363                position,
 3364                add,
 3365                click_count,
 3366            } => self.begin_selection(position, add, click_count, window, cx),
 3367            SelectPhase::BeginColumnar {
 3368                position,
 3369                goal_column,
 3370                reset,
 3371                mode,
 3372            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3373            SelectPhase::Extend {
 3374                position,
 3375                click_count,
 3376            } => self.extend_selection(position, click_count, window, cx),
 3377            SelectPhase::Update {
 3378                position,
 3379                goal_column,
 3380                scroll_delta,
 3381            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3382            SelectPhase::End => self.end_selection(window, cx),
 3383        }
 3384    }
 3385
 3386    fn extend_selection(
 3387        &mut self,
 3388        position: DisplayPoint,
 3389        click_count: usize,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3394        let tail = self.selections.newest::<usize>(cx).tail();
 3395        self.begin_selection(position, false, click_count, window, cx);
 3396
 3397        let position = position.to_offset(&display_map, Bias::Left);
 3398        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3399
 3400        let mut pending_selection = self
 3401            .selections
 3402            .pending_anchor()
 3403            .expect("extend_selection not called with pending selection");
 3404        if position >= tail {
 3405            pending_selection.start = tail_anchor;
 3406        } else {
 3407            pending_selection.end = tail_anchor;
 3408            pending_selection.reversed = true;
 3409        }
 3410
 3411        let mut pending_mode = self.selections.pending_mode().unwrap();
 3412        match &mut pending_mode {
 3413            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3414            _ => {}
 3415        }
 3416
 3417        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3418            SelectionEffects::scroll(Autoscroll::fit())
 3419        } else {
 3420            SelectionEffects::no_scroll()
 3421        };
 3422
 3423        self.change_selections(effects, window, cx, |s| {
 3424            s.set_pending(pending_selection, pending_mode)
 3425        });
 3426    }
 3427
 3428    fn begin_selection(
 3429        &mut self,
 3430        position: DisplayPoint,
 3431        add: bool,
 3432        click_count: usize,
 3433        window: &mut Window,
 3434        cx: &mut Context<Self>,
 3435    ) {
 3436        if !self.focus_handle.is_focused(window) {
 3437            self.last_focused_descendant = None;
 3438            window.focus(&self.focus_handle);
 3439        }
 3440
 3441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3442        let buffer = &display_map.buffer_snapshot;
 3443        let position = display_map.clip_point(position, Bias::Left);
 3444
 3445        let start;
 3446        let end;
 3447        let mode;
 3448        let mut auto_scroll;
 3449        match click_count {
 3450            1 => {
 3451                start = buffer.anchor_before(position.to_point(&display_map));
 3452                end = start;
 3453                mode = SelectMode::Character;
 3454                auto_scroll = true;
 3455            }
 3456            2 => {
 3457                let position = display_map
 3458                    .clip_point(position, Bias::Left)
 3459                    .to_offset(&display_map, Bias::Left);
 3460                let (range, _) = buffer.surrounding_word(position, false);
 3461                start = buffer.anchor_before(range.start);
 3462                end = buffer.anchor_before(range.end);
 3463                mode = SelectMode::Word(start..end);
 3464                auto_scroll = true;
 3465            }
 3466            3 => {
 3467                let position = display_map
 3468                    .clip_point(position, Bias::Left)
 3469                    .to_point(&display_map);
 3470                let line_start = display_map.prev_line_boundary(position).0;
 3471                let next_line_start = buffer.clip_point(
 3472                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3473                    Bias::Left,
 3474                );
 3475                start = buffer.anchor_before(line_start);
 3476                end = buffer.anchor_before(next_line_start);
 3477                mode = SelectMode::Line(start..end);
 3478                auto_scroll = true;
 3479            }
 3480            _ => {
 3481                start = buffer.anchor_before(0);
 3482                end = buffer.anchor_before(buffer.len());
 3483                mode = SelectMode::All;
 3484                auto_scroll = false;
 3485            }
 3486        }
 3487        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3488
 3489        let point_to_delete: Option<usize> = {
 3490            let selected_points: Vec<Selection<Point>> =
 3491                self.selections.disjoint_in_range(start..end, cx);
 3492
 3493            if !add || click_count > 1 {
 3494                None
 3495            } else if !selected_points.is_empty() {
 3496                Some(selected_points[0].id)
 3497            } else {
 3498                let clicked_point_already_selected =
 3499                    self.selections.disjoint.iter().find(|selection| {
 3500                        selection.start.to_point(buffer) == start.to_point(buffer)
 3501                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3502                    });
 3503
 3504                clicked_point_already_selected.map(|selection| selection.id)
 3505            }
 3506        };
 3507
 3508        let selections_count = self.selections.count();
 3509        let effects = if auto_scroll {
 3510            SelectionEffects::default()
 3511        } else {
 3512            SelectionEffects::no_scroll()
 3513        };
 3514
 3515        self.change_selections(effects, window, cx, |s| {
 3516            if let Some(point_to_delete) = point_to_delete {
 3517                s.delete(point_to_delete);
 3518
 3519                if selections_count == 1 {
 3520                    s.set_pending_anchor_range(start..end, mode);
 3521                }
 3522            } else {
 3523                if !add {
 3524                    s.clear_disjoint();
 3525                }
 3526
 3527                s.set_pending_anchor_range(start..end, mode);
 3528            }
 3529        });
 3530    }
 3531
 3532    fn begin_columnar_selection(
 3533        &mut self,
 3534        position: DisplayPoint,
 3535        goal_column: u32,
 3536        reset: bool,
 3537        mode: ColumnarMode,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) {
 3541        if !self.focus_handle.is_focused(window) {
 3542            self.last_focused_descendant = None;
 3543            window.focus(&self.focus_handle);
 3544        }
 3545
 3546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3547
 3548        if reset {
 3549            let pointer_position = display_map
 3550                .buffer_snapshot
 3551                .anchor_before(position.to_point(&display_map));
 3552
 3553            self.change_selections(
 3554                SelectionEffects::scroll(Autoscroll::newest()),
 3555                window,
 3556                cx,
 3557                |s| {
 3558                    s.clear_disjoint();
 3559                    s.set_pending_anchor_range(
 3560                        pointer_position..pointer_position,
 3561                        SelectMode::Character,
 3562                    );
 3563                },
 3564            );
 3565        };
 3566
 3567        let tail = self.selections.newest::<Point>(cx).tail();
 3568        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3569        self.columnar_selection_state = match mode {
 3570            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3571                selection_tail: selection_anchor,
 3572                display_point: if reset {
 3573                    if position.column() != goal_column {
 3574                        Some(DisplayPoint::new(position.row(), goal_column))
 3575                    } else {
 3576                        None
 3577                    }
 3578                } else {
 3579                    None
 3580                },
 3581            }),
 3582            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3583                selection_tail: selection_anchor,
 3584            }),
 3585        };
 3586
 3587        if !reset {
 3588            self.select_columns(position, goal_column, &display_map, window, cx);
 3589        }
 3590    }
 3591
 3592    fn update_selection(
 3593        &mut self,
 3594        position: DisplayPoint,
 3595        goal_column: u32,
 3596        scroll_delta: gpui::Point<f32>,
 3597        window: &mut Window,
 3598        cx: &mut Context<Self>,
 3599    ) {
 3600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3601
 3602        if self.columnar_selection_state.is_some() {
 3603            self.select_columns(position, goal_column, &display_map, window, cx);
 3604        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3605            let buffer = &display_map.buffer_snapshot;
 3606            let head;
 3607            let tail;
 3608            let mode = self.selections.pending_mode().unwrap();
 3609            match &mode {
 3610                SelectMode::Character => {
 3611                    head = position.to_point(&display_map);
 3612                    tail = pending.tail().to_point(buffer);
 3613                }
 3614                SelectMode::Word(original_range) => {
 3615                    let offset = display_map
 3616                        .clip_point(position, Bias::Left)
 3617                        .to_offset(&display_map, Bias::Left);
 3618                    let original_range = original_range.to_offset(buffer);
 3619
 3620                    let head_offset = if buffer.is_inside_word(offset, false)
 3621                        || original_range.contains(&offset)
 3622                    {
 3623                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3624                        if word_range.start < original_range.start {
 3625                            word_range.start
 3626                        } else {
 3627                            word_range.end
 3628                        }
 3629                    } else {
 3630                        offset
 3631                    };
 3632
 3633                    head = head_offset.to_point(buffer);
 3634                    if head_offset <= original_range.start {
 3635                        tail = original_range.end.to_point(buffer);
 3636                    } else {
 3637                        tail = original_range.start.to_point(buffer);
 3638                    }
 3639                }
 3640                SelectMode::Line(original_range) => {
 3641                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3642
 3643                    let position = display_map
 3644                        .clip_point(position, Bias::Left)
 3645                        .to_point(&display_map);
 3646                    let line_start = display_map.prev_line_boundary(position).0;
 3647                    let next_line_start = buffer.clip_point(
 3648                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3649                        Bias::Left,
 3650                    );
 3651
 3652                    if line_start < original_range.start {
 3653                        head = line_start
 3654                    } else {
 3655                        head = next_line_start
 3656                    }
 3657
 3658                    if head <= original_range.start {
 3659                        tail = original_range.end;
 3660                    } else {
 3661                        tail = original_range.start;
 3662                    }
 3663                }
 3664                SelectMode::All => {
 3665                    return;
 3666                }
 3667            };
 3668
 3669            if head < tail {
 3670                pending.start = buffer.anchor_before(head);
 3671                pending.end = buffer.anchor_before(tail);
 3672                pending.reversed = true;
 3673            } else {
 3674                pending.start = buffer.anchor_before(tail);
 3675                pending.end = buffer.anchor_before(head);
 3676                pending.reversed = false;
 3677            }
 3678
 3679            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3680                s.set_pending(pending, mode);
 3681            });
 3682        } else {
 3683            log::error!("update_selection dispatched with no pending selection");
 3684            return;
 3685        }
 3686
 3687        self.apply_scroll_delta(scroll_delta, window, cx);
 3688        cx.notify();
 3689    }
 3690
 3691    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3692        self.columnar_selection_state.take();
 3693        if self.selections.pending_anchor().is_some() {
 3694            let selections = self.selections.all::<usize>(cx);
 3695            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3696                s.select(selections);
 3697                s.clear_pending();
 3698            });
 3699        }
 3700    }
 3701
 3702    fn select_columns(
 3703        &mut self,
 3704        head: DisplayPoint,
 3705        goal_column: u32,
 3706        display_map: &DisplaySnapshot,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3711            return;
 3712        };
 3713
 3714        let tail = match columnar_state {
 3715            ColumnarSelectionState::FromMouse {
 3716                selection_tail,
 3717                display_point,
 3718            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3719            ColumnarSelectionState::FromSelection { selection_tail } => {
 3720                selection_tail.to_display_point(&display_map)
 3721            }
 3722        };
 3723
 3724        let start_row = cmp::min(tail.row(), head.row());
 3725        let end_row = cmp::max(tail.row(), head.row());
 3726        let start_column = cmp::min(tail.column(), goal_column);
 3727        let end_column = cmp::max(tail.column(), goal_column);
 3728        let reversed = start_column < tail.column();
 3729
 3730        let selection_ranges = (start_row.0..=end_row.0)
 3731            .map(DisplayRow)
 3732            .filter_map(|row| {
 3733                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3734                    || start_column <= display_map.line_len(row))
 3735                    && !display_map.is_block_line(row)
 3736                {
 3737                    let start = display_map
 3738                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3739                        .to_point(display_map);
 3740                    let end = display_map
 3741                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3742                        .to_point(display_map);
 3743                    if reversed {
 3744                        Some(end..start)
 3745                    } else {
 3746                        Some(start..end)
 3747                    }
 3748                } else {
 3749                    None
 3750                }
 3751            })
 3752            .collect::<Vec<_>>();
 3753
 3754        let ranges = match columnar_state {
 3755            ColumnarSelectionState::FromMouse { .. } => {
 3756                let mut non_empty_ranges = selection_ranges
 3757                    .iter()
 3758                    .filter(|selection_range| selection_range.start != selection_range.end)
 3759                    .peekable();
 3760                if non_empty_ranges.peek().is_some() {
 3761                    non_empty_ranges.cloned().collect()
 3762                } else {
 3763                    selection_ranges
 3764                }
 3765            }
 3766            _ => selection_ranges,
 3767        };
 3768
 3769        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3770            s.select_ranges(ranges);
 3771        });
 3772        cx.notify();
 3773    }
 3774
 3775    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3776        self.selections
 3777            .all_adjusted(cx)
 3778            .iter()
 3779            .any(|selection| !selection.is_empty())
 3780    }
 3781
 3782    pub fn has_pending_nonempty_selection(&self) -> bool {
 3783        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3784            Some(Selection { start, end, .. }) => start != end,
 3785            None => false,
 3786        };
 3787
 3788        pending_nonempty_selection
 3789            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3790    }
 3791
 3792    pub fn has_pending_selection(&self) -> bool {
 3793        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3794    }
 3795
 3796    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3797        self.selection_mark_mode = false;
 3798        self.selection_drag_state = SelectionDragState::None;
 3799
 3800        if self.clear_expanded_diff_hunks(cx) {
 3801            cx.notify();
 3802            return;
 3803        }
 3804        if self.dismiss_menus_and_popups(true, window, cx) {
 3805            return;
 3806        }
 3807
 3808        if self.mode.is_full()
 3809            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3810        {
 3811            return;
 3812        }
 3813
 3814        cx.propagate();
 3815    }
 3816
 3817    pub fn dismiss_menus_and_popups(
 3818        &mut self,
 3819        is_user_requested: bool,
 3820        window: &mut Window,
 3821        cx: &mut Context<Self>,
 3822    ) -> bool {
 3823        if self.take_rename(false, window, cx).is_some() {
 3824            return true;
 3825        }
 3826
 3827        if hide_hover(self, cx) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3832            return true;
 3833        }
 3834
 3835        if self.hide_context_menu(window, cx).is_some() {
 3836            return true;
 3837        }
 3838
 3839        if self.mouse_context_menu.take().is_some() {
 3840            return true;
 3841        }
 3842
 3843        if is_user_requested && self.discard_inline_completion(true, cx) {
 3844            return true;
 3845        }
 3846
 3847        if self.snippet_stack.pop().is_some() {
 3848            return true;
 3849        }
 3850
 3851        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3852            self.dismiss_diagnostics(cx);
 3853            return true;
 3854        }
 3855
 3856        false
 3857    }
 3858
 3859    fn linked_editing_ranges_for(
 3860        &self,
 3861        selection: Range<text::Anchor>,
 3862        cx: &App,
 3863    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3864        if self.linked_edit_ranges.is_empty() {
 3865            return None;
 3866        }
 3867        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3868            selection.end.buffer_id.and_then(|end_buffer_id| {
 3869                if selection.start.buffer_id != Some(end_buffer_id) {
 3870                    return None;
 3871                }
 3872                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3873                let snapshot = buffer.read(cx).snapshot();
 3874                self.linked_edit_ranges
 3875                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3876                    .map(|ranges| (ranges, snapshot, buffer))
 3877            })?;
 3878        use text::ToOffset as TO;
 3879        // find offset from the start of current range to current cursor position
 3880        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3881
 3882        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3883        let start_difference = start_offset - start_byte_offset;
 3884        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3885        let end_difference = end_offset - start_byte_offset;
 3886        // Current range has associated linked ranges.
 3887        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3888        for range in linked_ranges.iter() {
 3889            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3890            let end_offset = start_offset + end_difference;
 3891            let start_offset = start_offset + start_difference;
 3892            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3893                continue;
 3894            }
 3895            if self.selections.disjoint_anchor_ranges().any(|s| {
 3896                if s.start.buffer_id != selection.start.buffer_id
 3897                    || s.end.buffer_id != selection.end.buffer_id
 3898                {
 3899                    return false;
 3900                }
 3901                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3902                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3903            }) {
 3904                continue;
 3905            }
 3906            let start = buffer_snapshot.anchor_after(start_offset);
 3907            let end = buffer_snapshot.anchor_after(end_offset);
 3908            linked_edits
 3909                .entry(buffer.clone())
 3910                .or_default()
 3911                .push(start..end);
 3912        }
 3913        Some(linked_edits)
 3914    }
 3915
 3916    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3917        let text: Arc<str> = text.into();
 3918
 3919        if self.read_only(cx) {
 3920            return;
 3921        }
 3922
 3923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3924
 3925        let selections = self.selections.all_adjusted(cx);
 3926        let mut bracket_inserted = false;
 3927        let mut edits = Vec::new();
 3928        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3929        let mut new_selections = Vec::with_capacity(selections.len());
 3930        let mut new_autoclose_regions = Vec::new();
 3931        let snapshot = self.buffer.read(cx).read(cx);
 3932        let mut clear_linked_edit_ranges = false;
 3933
 3934        for (selection, autoclose_region) in
 3935            self.selections_with_autoclose_regions(selections, &snapshot)
 3936        {
 3937            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3938                // Determine if the inserted text matches the opening or closing
 3939                // bracket of any of this language's bracket pairs.
 3940                let mut bracket_pair = None;
 3941                let mut is_bracket_pair_start = false;
 3942                let mut is_bracket_pair_end = false;
 3943                if !text.is_empty() {
 3944                    let mut bracket_pair_matching_end = None;
 3945                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3946                    //  and they are removing the character that triggered IME popup.
 3947                    for (pair, enabled) in scope.brackets() {
 3948                        if !pair.close && !pair.surround {
 3949                            continue;
 3950                        }
 3951
 3952                        if enabled && pair.start.ends_with(text.as_ref()) {
 3953                            let prefix_len = pair.start.len() - text.len();
 3954                            let preceding_text_matches_prefix = prefix_len == 0
 3955                                || (selection.start.column >= (prefix_len as u32)
 3956                                    && snapshot.contains_str_at(
 3957                                        Point::new(
 3958                                            selection.start.row,
 3959                                            selection.start.column - (prefix_len as u32),
 3960                                        ),
 3961                                        &pair.start[..prefix_len],
 3962                                    ));
 3963                            if preceding_text_matches_prefix {
 3964                                bracket_pair = Some(pair.clone());
 3965                                is_bracket_pair_start = true;
 3966                                break;
 3967                            }
 3968                        }
 3969                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3970                        {
 3971                            // take first bracket pair matching end, but don't break in case a later bracket
 3972                            // pair matches start
 3973                            bracket_pair_matching_end = Some(pair.clone());
 3974                        }
 3975                    }
 3976                    if let Some(end) = bracket_pair_matching_end
 3977                        && bracket_pair.is_none()
 3978                    {
 3979                        bracket_pair = Some(end);
 3980                        is_bracket_pair_end = true;
 3981                    }
 3982                }
 3983
 3984                if let Some(bracket_pair) = bracket_pair {
 3985                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3986                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3987                    let auto_surround =
 3988                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3989                    if selection.is_empty() {
 3990                        if is_bracket_pair_start {
 3991                            // If the inserted text is a suffix of an opening bracket and the
 3992                            // selection is preceded by the rest of the opening bracket, then
 3993                            // insert the closing bracket.
 3994                            let following_text_allows_autoclose = snapshot
 3995                                .chars_at(selection.start)
 3996                                .next()
 3997                                .map_or(true, |c| scope.should_autoclose_before(c));
 3998
 3999                            let preceding_text_allows_autoclose = selection.start.column == 0
 4000                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4001                                    true,
 4002                                    |c| {
 4003                                        bracket_pair.start != bracket_pair.end
 4004                                            || !snapshot
 4005                                                .char_classifier_at(selection.start)
 4006                                                .is_word(c)
 4007                                    },
 4008                                );
 4009
 4010                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4011                                && bracket_pair.start.len() == 1
 4012                            {
 4013                                let target = bracket_pair.start.chars().next().unwrap();
 4014                                let current_line_count = snapshot
 4015                                    .reversed_chars_at(selection.start)
 4016                                    .take_while(|&c| c != '\n')
 4017                                    .filter(|&c| c == target)
 4018                                    .count();
 4019                                current_line_count % 2 == 1
 4020                            } else {
 4021                                false
 4022                            };
 4023
 4024                            if autoclose
 4025                                && bracket_pair.close
 4026                                && following_text_allows_autoclose
 4027                                && preceding_text_allows_autoclose
 4028                                && !is_closing_quote
 4029                            {
 4030                                let anchor = snapshot.anchor_before(selection.end);
 4031                                new_selections.push((selection.map(|_| anchor), text.len()));
 4032                                new_autoclose_regions.push((
 4033                                    anchor,
 4034                                    text.len(),
 4035                                    selection.id,
 4036                                    bracket_pair.clone(),
 4037                                ));
 4038                                edits.push((
 4039                                    selection.range(),
 4040                                    format!("{}{}", text, bracket_pair.end).into(),
 4041                                ));
 4042                                bracket_inserted = true;
 4043                                continue;
 4044                            }
 4045                        }
 4046
 4047                        if let Some(region) = autoclose_region {
 4048                            // If the selection is followed by an auto-inserted closing bracket,
 4049                            // then don't insert that closing bracket again; just move the selection
 4050                            // past the closing bracket.
 4051                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4052                                && text.as_ref() == region.pair.end.as_str()
 4053                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4054                            if should_skip {
 4055                                let anchor = snapshot.anchor_after(selection.end);
 4056                                new_selections
 4057                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4058                                continue;
 4059                            }
 4060                        }
 4061
 4062                        let always_treat_brackets_as_autoclosed = snapshot
 4063                            .language_settings_at(selection.start, cx)
 4064                            .always_treat_brackets_as_autoclosed;
 4065                        if always_treat_brackets_as_autoclosed
 4066                            && is_bracket_pair_end
 4067                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4068                        {
 4069                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4070                            // and the inserted text is a closing bracket and the selection is followed
 4071                            // by the closing bracket then move the selection past the closing bracket.
 4072                            let anchor = snapshot.anchor_after(selection.end);
 4073                            new_selections.push((selection.map(|_| anchor), text.len()));
 4074                            continue;
 4075                        }
 4076                    }
 4077                    // If an opening bracket is 1 character long and is typed while
 4078                    // text is selected, then surround that text with the bracket pair.
 4079                    else if auto_surround
 4080                        && bracket_pair.surround
 4081                        && is_bracket_pair_start
 4082                        && bracket_pair.start.chars().count() == 1
 4083                    {
 4084                        edits.push((selection.start..selection.start, text.clone()));
 4085                        edits.push((
 4086                            selection.end..selection.end,
 4087                            bracket_pair.end.as_str().into(),
 4088                        ));
 4089                        bracket_inserted = true;
 4090                        new_selections.push((
 4091                            Selection {
 4092                                id: selection.id,
 4093                                start: snapshot.anchor_after(selection.start),
 4094                                end: snapshot.anchor_before(selection.end),
 4095                                reversed: selection.reversed,
 4096                                goal: selection.goal,
 4097                            },
 4098                            0,
 4099                        ));
 4100                        continue;
 4101                    }
 4102                }
 4103            }
 4104
 4105            if self.auto_replace_emoji_shortcode
 4106                && selection.is_empty()
 4107                && text.as_ref().ends_with(':')
 4108            {
 4109                if let Some(possible_emoji_short_code) =
 4110                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4111                {
 4112                    if !possible_emoji_short_code.is_empty() {
 4113                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4114                            let emoji_shortcode_start = Point::new(
 4115                                selection.start.row,
 4116                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4117                            );
 4118
 4119                            // Remove shortcode from buffer
 4120                            edits.push((
 4121                                emoji_shortcode_start..selection.start,
 4122                                "".to_string().into(),
 4123                            ));
 4124                            new_selections.push((
 4125                                Selection {
 4126                                    id: selection.id,
 4127                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4128                                    end: snapshot.anchor_before(selection.start),
 4129                                    reversed: selection.reversed,
 4130                                    goal: selection.goal,
 4131                                },
 4132                                0,
 4133                            ));
 4134
 4135                            // Insert emoji
 4136                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4137                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4138                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4139
 4140                            continue;
 4141                        }
 4142                    }
 4143                }
 4144            }
 4145
 4146            // If not handling any auto-close operation, then just replace the selected
 4147            // text with the given input and move the selection to the end of the
 4148            // newly inserted text.
 4149            let anchor = snapshot.anchor_after(selection.end);
 4150            if !self.linked_edit_ranges.is_empty() {
 4151                let start_anchor = snapshot.anchor_before(selection.start);
 4152
 4153                let is_word_char = text.chars().next().map_or(true, |char| {
 4154                    let classifier = snapshot
 4155                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4156                        .ignore_punctuation(true);
 4157                    classifier.is_word(char)
 4158                });
 4159
 4160                if is_word_char {
 4161                    if let Some(ranges) = self
 4162                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4163                    {
 4164                        for (buffer, edits) in ranges {
 4165                            linked_edits
 4166                                .entry(buffer.clone())
 4167                                .or_default()
 4168                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4169                        }
 4170                    }
 4171                } else {
 4172                    clear_linked_edit_ranges = true;
 4173                }
 4174            }
 4175
 4176            new_selections.push((selection.map(|_| anchor), 0));
 4177            edits.push((selection.start..selection.end, text.clone()));
 4178        }
 4179
 4180        drop(snapshot);
 4181
 4182        self.transact(window, cx, |this, window, cx| {
 4183            if clear_linked_edit_ranges {
 4184                this.linked_edit_ranges.clear();
 4185            }
 4186            let initial_buffer_versions =
 4187                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4188
 4189            this.buffer.update(cx, |buffer, cx| {
 4190                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4191            });
 4192            for (buffer, edits) in linked_edits {
 4193                buffer.update(cx, |buffer, cx| {
 4194                    let snapshot = buffer.snapshot();
 4195                    let edits = edits
 4196                        .into_iter()
 4197                        .map(|(range, text)| {
 4198                            use text::ToPoint as TP;
 4199                            let end_point = TP::to_point(&range.end, &snapshot);
 4200                            let start_point = TP::to_point(&range.start, &snapshot);
 4201                            (start_point..end_point, text)
 4202                        })
 4203                        .sorted_by_key(|(range, _)| range.start);
 4204                    buffer.edit(edits, None, cx);
 4205                })
 4206            }
 4207            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4208            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4209            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4210            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4211                .zip(new_selection_deltas)
 4212                .map(|(selection, delta)| Selection {
 4213                    id: selection.id,
 4214                    start: selection.start + delta,
 4215                    end: selection.end + delta,
 4216                    reversed: selection.reversed,
 4217                    goal: SelectionGoal::None,
 4218                })
 4219                .collect::<Vec<_>>();
 4220
 4221            let mut i = 0;
 4222            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4223                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4224                let start = map.buffer_snapshot.anchor_before(position);
 4225                let end = map.buffer_snapshot.anchor_after(position);
 4226                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4227                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4228                        Ordering::Less => i += 1,
 4229                        Ordering::Greater => break,
 4230                        Ordering::Equal => {
 4231                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4232                                Ordering::Less => i += 1,
 4233                                Ordering::Equal => break,
 4234                                Ordering::Greater => break,
 4235                            }
 4236                        }
 4237                    }
 4238                }
 4239                this.autoclose_regions.insert(
 4240                    i,
 4241                    AutocloseRegion {
 4242                        selection_id,
 4243                        range: start..end,
 4244                        pair,
 4245                    },
 4246                );
 4247            }
 4248
 4249            let had_active_inline_completion = this.has_active_inline_completion();
 4250            this.change_selections(
 4251                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4252                window,
 4253                cx,
 4254                |s| s.select(new_selections),
 4255            );
 4256
 4257            if !bracket_inserted {
 4258                if let Some(on_type_format_task) =
 4259                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4260                {
 4261                    on_type_format_task.detach_and_log_err(cx);
 4262                }
 4263            }
 4264
 4265            let editor_settings = EditorSettings::get_global(cx);
 4266            if bracket_inserted
 4267                && (editor_settings.auto_signature_help
 4268                    || editor_settings.show_signature_help_after_edits)
 4269            {
 4270                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4271            }
 4272
 4273            let trigger_in_words =
 4274                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4275            if this.hard_wrap.is_some() {
 4276                let latest: Range<Point> = this.selections.newest(cx).range();
 4277                if latest.is_empty()
 4278                    && this
 4279                        .buffer()
 4280                        .read(cx)
 4281                        .snapshot(cx)
 4282                        .line_len(MultiBufferRow(latest.start.row))
 4283                        == latest.start.column
 4284                {
 4285                    this.rewrap_impl(
 4286                        RewrapOptions {
 4287                            override_language_settings: true,
 4288                            preserve_existing_whitespace: true,
 4289                        },
 4290                        cx,
 4291                    )
 4292                }
 4293            }
 4294            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4295            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4296            this.refresh_inline_completion(true, false, window, cx);
 4297            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4298        });
 4299    }
 4300
 4301    fn find_possible_emoji_shortcode_at_position(
 4302        snapshot: &MultiBufferSnapshot,
 4303        position: Point,
 4304    ) -> Option<String> {
 4305        let mut chars = Vec::new();
 4306        let mut found_colon = false;
 4307        for char in snapshot.reversed_chars_at(position).take(100) {
 4308            // Found a possible emoji shortcode in the middle of the buffer
 4309            if found_colon {
 4310                if char.is_whitespace() {
 4311                    chars.reverse();
 4312                    return Some(chars.iter().collect());
 4313                }
 4314                // If the previous character is not a whitespace, we are in the middle of a word
 4315                // and we only want to complete the shortcode if the word is made up of other emojis
 4316                let mut containing_word = String::new();
 4317                for ch in snapshot
 4318                    .reversed_chars_at(position)
 4319                    .skip(chars.len() + 1)
 4320                    .take(100)
 4321                {
 4322                    if ch.is_whitespace() {
 4323                        break;
 4324                    }
 4325                    containing_word.push(ch);
 4326                }
 4327                let containing_word = containing_word.chars().rev().collect::<String>();
 4328                if util::word_consists_of_emojis(containing_word.as_str()) {
 4329                    chars.reverse();
 4330                    return Some(chars.iter().collect());
 4331                }
 4332            }
 4333
 4334            if char.is_whitespace() || !char.is_ascii() {
 4335                return None;
 4336            }
 4337            if char == ':' {
 4338                found_colon = true;
 4339            } else {
 4340                chars.push(char);
 4341            }
 4342        }
 4343        // Found a possible emoji shortcode at the beginning of the buffer
 4344        chars.reverse();
 4345        Some(chars.iter().collect())
 4346    }
 4347
 4348    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4350        self.transact(window, cx, |this, window, cx| {
 4351            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4352                let selections = this.selections.all::<usize>(cx);
 4353                let multi_buffer = this.buffer.read(cx);
 4354                let buffer = multi_buffer.snapshot(cx);
 4355                selections
 4356                    .iter()
 4357                    .map(|selection| {
 4358                        let start_point = selection.start.to_point(&buffer);
 4359                        let mut existing_indent =
 4360                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4361                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4362                        let start = selection.start;
 4363                        let end = selection.end;
 4364                        let selection_is_empty = start == end;
 4365                        let language_scope = buffer.language_scope_at(start);
 4366                        let (
 4367                            comment_delimiter,
 4368                            doc_delimiter,
 4369                            insert_extra_newline,
 4370                            indent_on_newline,
 4371                            indent_on_extra_newline,
 4372                        ) = if let Some(language) = &language_scope {
 4373                            let mut insert_extra_newline =
 4374                                insert_extra_newline_brackets(&buffer, start..end, language)
 4375                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4376
 4377                            // Comment extension on newline is allowed only for cursor selections
 4378                            let comment_delimiter = maybe!({
 4379                                if !selection_is_empty {
 4380                                    return None;
 4381                                }
 4382
 4383                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4384                                    return None;
 4385                                }
 4386
 4387                                let delimiters = language.line_comment_prefixes();
 4388                                let max_len_of_delimiter =
 4389                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4390                                let (snapshot, range) =
 4391                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4392
 4393                                let num_of_whitespaces = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .take_while(|c| c.is_whitespace())
 4396                                    .count();
 4397                                let comment_candidate = snapshot
 4398                                    .chars_for_range(range.clone())
 4399                                    .skip(num_of_whitespaces)
 4400                                    .take(max_len_of_delimiter)
 4401                                    .collect::<String>();
 4402                                let (delimiter, trimmed_len) = delimiters
 4403                                    .iter()
 4404                                    .filter_map(|delimiter| {
 4405                                        let prefix = delimiter.trim_end();
 4406                                        if comment_candidate.starts_with(prefix) {
 4407                                            Some((delimiter, prefix.len()))
 4408                                        } else {
 4409                                            None
 4410                                        }
 4411                                    })
 4412                                    .max_by_key(|(_, len)| *len)?;
 4413
 4414                                if let Some(BlockCommentConfig {
 4415                                    start: block_start, ..
 4416                                }) = language.block_comment()
 4417                                {
 4418                                    let block_start_trimmed = block_start.trim_end();
 4419                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4420                                        let line_content = snapshot
 4421                                            .chars_for_range(range)
 4422                                            .skip(num_of_whitespaces)
 4423                                            .take(block_start_trimmed.len())
 4424                                            .collect::<String>();
 4425
 4426                                        if line_content.starts_with(block_start_trimmed) {
 4427                                            return None;
 4428                                        }
 4429                                    }
 4430                                }
 4431
 4432                                let cursor_is_placed_after_comment_marker =
 4433                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4434                                if cursor_is_placed_after_comment_marker {
 4435                                    Some(delimiter.clone())
 4436                                } else {
 4437                                    None
 4438                                }
 4439                            });
 4440
 4441                            let mut indent_on_newline = IndentSize::spaces(0);
 4442                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4443
 4444                            let doc_delimiter = maybe!({
 4445                                if !selection_is_empty {
 4446                                    return None;
 4447                                }
 4448
 4449                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4450                                    return None;
 4451                                }
 4452
 4453                                let BlockCommentConfig {
 4454                                    start: start_tag,
 4455                                    end: end_tag,
 4456                                    prefix: delimiter,
 4457                                    tab_size: len,
 4458                                } = language.documentation_comment()?;
 4459                                let is_within_block_comment = buffer
 4460                                    .language_scope_at(start_point)
 4461                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4462                                if !is_within_block_comment {
 4463                                    return None;
 4464                                }
 4465
 4466                                let (snapshot, range) =
 4467                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4468
 4469                                let num_of_whitespaces = snapshot
 4470                                    .chars_for_range(range.clone())
 4471                                    .take_while(|c| c.is_whitespace())
 4472                                    .count();
 4473
 4474                                // 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.
 4475                                let column = start_point.column;
 4476                                let cursor_is_after_start_tag = {
 4477                                    let start_tag_len = start_tag.len();
 4478                                    let start_tag_line = snapshot
 4479                                        .chars_for_range(range.clone())
 4480                                        .skip(num_of_whitespaces)
 4481                                        .take(start_tag_len)
 4482                                        .collect::<String>();
 4483                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4484                                        num_of_whitespaces + start_tag_len <= column as usize
 4485                                    } else {
 4486                                        false
 4487                                    }
 4488                                };
 4489
 4490                                let cursor_is_after_delimiter = {
 4491                                    let delimiter_trim = delimiter.trim_end();
 4492                                    let delimiter_line = snapshot
 4493                                        .chars_for_range(range.clone())
 4494                                        .skip(num_of_whitespaces)
 4495                                        .take(delimiter_trim.len())
 4496                                        .collect::<String>();
 4497                                    if delimiter_line.starts_with(delimiter_trim) {
 4498                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4499                                    } else {
 4500                                        false
 4501                                    }
 4502                                };
 4503
 4504                                let cursor_is_before_end_tag_if_exists = {
 4505                                    let mut char_position = 0u32;
 4506                                    let mut end_tag_offset = None;
 4507
 4508                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4509                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4510                                            let chars_before_match =
 4511                                                chunk[..byte_pos].chars().count() as u32;
 4512                                            end_tag_offset =
 4513                                                Some(char_position + chars_before_match);
 4514                                            break 'outer;
 4515                                        }
 4516                                        char_position += chunk.chars().count() as u32;
 4517                                    }
 4518
 4519                                    if let Some(end_tag_offset) = end_tag_offset {
 4520                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4521                                        if cursor_is_after_start_tag {
 4522                                            if cursor_is_before_end_tag {
 4523                                                insert_extra_newline = true;
 4524                                            }
 4525                                            let cursor_is_at_start_of_end_tag =
 4526                                                column == end_tag_offset;
 4527                                            if cursor_is_at_start_of_end_tag {
 4528                                                indent_on_extra_newline.len = *len;
 4529                                            }
 4530                                        }
 4531                                        cursor_is_before_end_tag
 4532                                    } else {
 4533                                        true
 4534                                    }
 4535                                };
 4536
 4537                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4538                                    && cursor_is_before_end_tag_if_exists
 4539                                {
 4540                                    if cursor_is_after_start_tag {
 4541                                        indent_on_newline.len = *len;
 4542                                    }
 4543                                    Some(delimiter.clone())
 4544                                } else {
 4545                                    None
 4546                                }
 4547                            });
 4548
 4549                            (
 4550                                comment_delimiter,
 4551                                doc_delimiter,
 4552                                insert_extra_newline,
 4553                                indent_on_newline,
 4554                                indent_on_extra_newline,
 4555                            )
 4556                        } else {
 4557                            (
 4558                                None,
 4559                                None,
 4560                                false,
 4561                                IndentSize::default(),
 4562                                IndentSize::default(),
 4563                            )
 4564                        };
 4565
 4566                        let prevent_auto_indent = doc_delimiter.is_some();
 4567                        let delimiter = comment_delimiter.or(doc_delimiter);
 4568
 4569                        let capacity_for_delimiter =
 4570                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4571                        let mut new_text = String::with_capacity(
 4572                            1 + capacity_for_delimiter
 4573                                + existing_indent.len as usize
 4574                                + indent_on_newline.len as usize
 4575                                + indent_on_extra_newline.len as usize,
 4576                        );
 4577                        new_text.push('\n');
 4578                        new_text.extend(existing_indent.chars());
 4579                        new_text.extend(indent_on_newline.chars());
 4580
 4581                        if let Some(delimiter) = &delimiter {
 4582                            new_text.push_str(delimiter);
 4583                        }
 4584
 4585                        if insert_extra_newline {
 4586                            new_text.push('\n');
 4587                            new_text.extend(existing_indent.chars());
 4588                            new_text.extend(indent_on_extra_newline.chars());
 4589                        }
 4590
 4591                        let anchor = buffer.anchor_after(end);
 4592                        let new_selection = selection.map(|_| anchor);
 4593                        (
 4594                            ((start..end, new_text), prevent_auto_indent),
 4595                            (insert_extra_newline, new_selection),
 4596                        )
 4597                    })
 4598                    .unzip()
 4599            };
 4600
 4601            let mut auto_indent_edits = Vec::new();
 4602            let mut edits = Vec::new();
 4603            for (edit, prevent_auto_indent) in edits_with_flags {
 4604                if prevent_auto_indent {
 4605                    edits.push(edit);
 4606                } else {
 4607                    auto_indent_edits.push(edit);
 4608                }
 4609            }
 4610            if !edits.is_empty() {
 4611                this.edit(edits, cx);
 4612            }
 4613            if !auto_indent_edits.is_empty() {
 4614                this.edit_with_autoindent(auto_indent_edits, cx);
 4615            }
 4616
 4617            let buffer = this.buffer.read(cx).snapshot(cx);
 4618            let new_selections = selection_info
 4619                .into_iter()
 4620                .map(|(extra_newline_inserted, new_selection)| {
 4621                    let mut cursor = new_selection.end.to_point(&buffer);
 4622                    if extra_newline_inserted {
 4623                        cursor.row -= 1;
 4624                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4625                    }
 4626                    new_selection.map(|_| cursor)
 4627                })
 4628                .collect();
 4629
 4630            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4631            this.refresh_inline_completion(true, false, window, cx);
 4632        });
 4633    }
 4634
 4635    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4637
 4638        let buffer = self.buffer.read(cx);
 4639        let snapshot = buffer.snapshot(cx);
 4640
 4641        let mut edits = Vec::new();
 4642        let mut rows = Vec::new();
 4643
 4644        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4645            let cursor = selection.head();
 4646            let row = cursor.row;
 4647
 4648            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4649
 4650            let newline = "\n".to_string();
 4651            edits.push((start_of_line..start_of_line, newline));
 4652
 4653            rows.push(row + rows_inserted as u32);
 4654        }
 4655
 4656        self.transact(window, cx, |editor, window, cx| {
 4657            editor.edit(edits, cx);
 4658
 4659            editor.change_selections(Default::default(), window, cx, |s| {
 4660                let mut index = 0;
 4661                s.move_cursors_with(|map, _, _| {
 4662                    let row = rows[index];
 4663                    index += 1;
 4664
 4665                    let point = Point::new(row, 0);
 4666                    let boundary = map.next_line_boundary(point).1;
 4667                    let clipped = map.clip_point(boundary, Bias::Left);
 4668
 4669                    (clipped, SelectionGoal::None)
 4670                });
 4671            });
 4672
 4673            let mut indent_edits = Vec::new();
 4674            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4675            for row in rows {
 4676                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4677                for (row, indent) in indents {
 4678                    if indent.len == 0 {
 4679                        continue;
 4680                    }
 4681
 4682                    let text = match indent.kind {
 4683                        IndentKind::Space => " ".repeat(indent.len as usize),
 4684                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4685                    };
 4686                    let point = Point::new(row.0, 0);
 4687                    indent_edits.push((point..point, text));
 4688                }
 4689            }
 4690            editor.edit(indent_edits, cx);
 4691        });
 4692    }
 4693
 4694    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4696
 4697        let buffer = self.buffer.read(cx);
 4698        let snapshot = buffer.snapshot(cx);
 4699
 4700        let mut edits = Vec::new();
 4701        let mut rows = Vec::new();
 4702        let mut rows_inserted = 0;
 4703
 4704        for selection in self.selections.all_adjusted(cx) {
 4705            let cursor = selection.head();
 4706            let row = cursor.row;
 4707
 4708            let point = Point::new(row + 1, 0);
 4709            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4710
 4711            let newline = "\n".to_string();
 4712            edits.push((start_of_line..start_of_line, newline));
 4713
 4714            rows_inserted += 1;
 4715            rows.push(row + rows_inserted);
 4716        }
 4717
 4718        self.transact(window, cx, |editor, window, cx| {
 4719            editor.edit(edits, cx);
 4720
 4721            editor.change_selections(Default::default(), window, cx, |s| {
 4722                let mut index = 0;
 4723                s.move_cursors_with(|map, _, _| {
 4724                    let row = rows[index];
 4725                    index += 1;
 4726
 4727                    let point = Point::new(row, 0);
 4728                    let boundary = map.next_line_boundary(point).1;
 4729                    let clipped = map.clip_point(boundary, Bias::Left);
 4730
 4731                    (clipped, SelectionGoal::None)
 4732                });
 4733            });
 4734
 4735            let mut indent_edits = Vec::new();
 4736            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4737            for row in rows {
 4738                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4739                for (row, indent) in indents {
 4740                    if indent.len == 0 {
 4741                        continue;
 4742                    }
 4743
 4744                    let text = match indent.kind {
 4745                        IndentKind::Space => " ".repeat(indent.len as usize),
 4746                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4747                    };
 4748                    let point = Point::new(row.0, 0);
 4749                    indent_edits.push((point..point, text));
 4750                }
 4751            }
 4752            editor.edit(indent_edits, cx);
 4753        });
 4754    }
 4755
 4756    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4757        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4758            original_indent_columns: Vec::new(),
 4759        });
 4760        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4761    }
 4762
 4763    fn insert_with_autoindent_mode(
 4764        &mut self,
 4765        text: &str,
 4766        autoindent_mode: Option<AutoindentMode>,
 4767        window: &mut Window,
 4768        cx: &mut Context<Self>,
 4769    ) {
 4770        if self.read_only(cx) {
 4771            return;
 4772        }
 4773
 4774        let text: Arc<str> = text.into();
 4775        self.transact(window, cx, |this, window, cx| {
 4776            let old_selections = this.selections.all_adjusted(cx);
 4777            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4778                let anchors = {
 4779                    let snapshot = buffer.read(cx);
 4780                    old_selections
 4781                        .iter()
 4782                        .map(|s| {
 4783                            let anchor = snapshot.anchor_after(s.head());
 4784                            s.map(|_| anchor)
 4785                        })
 4786                        .collect::<Vec<_>>()
 4787                };
 4788                buffer.edit(
 4789                    old_selections
 4790                        .iter()
 4791                        .map(|s| (s.start..s.end, text.clone())),
 4792                    autoindent_mode,
 4793                    cx,
 4794                );
 4795                anchors
 4796            });
 4797
 4798            this.change_selections(Default::default(), window, cx, |s| {
 4799                s.select_anchors(selection_anchors);
 4800            });
 4801
 4802            cx.notify();
 4803        });
 4804    }
 4805
 4806    fn trigger_completion_on_input(
 4807        &mut self,
 4808        text: &str,
 4809        trigger_in_words: bool,
 4810        window: &mut Window,
 4811        cx: &mut Context<Self>,
 4812    ) {
 4813        let completions_source = self
 4814            .context_menu
 4815            .borrow()
 4816            .as_ref()
 4817            .and_then(|menu| match menu {
 4818                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4819                CodeContextMenu::CodeActions(_) => None,
 4820            });
 4821
 4822        match completions_source {
 4823            Some(CompletionsMenuSource::Words) => {
 4824                self.show_word_completions(&ShowWordCompletions, window, cx)
 4825            }
 4826            Some(CompletionsMenuSource::Normal)
 4827            | Some(CompletionsMenuSource::SnippetChoices)
 4828            | None
 4829                if self.is_completion_trigger(
 4830                    text,
 4831                    trigger_in_words,
 4832                    completions_source.is_some(),
 4833                    cx,
 4834                ) =>
 4835            {
 4836                self.show_completions(
 4837                    &ShowCompletions {
 4838                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4839                    },
 4840                    window,
 4841                    cx,
 4842                )
 4843            }
 4844            _ => {
 4845                self.hide_context_menu(window, cx);
 4846            }
 4847        }
 4848    }
 4849
 4850    fn is_completion_trigger(
 4851        &self,
 4852        text: &str,
 4853        trigger_in_words: bool,
 4854        menu_is_open: bool,
 4855        cx: &mut Context<Self>,
 4856    ) -> bool {
 4857        let position = self.selections.newest_anchor().head();
 4858        let multibuffer = self.buffer.read(cx);
 4859        let Some(buffer) = position
 4860            .buffer_id
 4861            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4862        else {
 4863            return false;
 4864        };
 4865
 4866        if let Some(completion_provider) = &self.completion_provider {
 4867            completion_provider.is_completion_trigger(
 4868                &buffer,
 4869                position.text_anchor,
 4870                text,
 4871                trigger_in_words,
 4872                menu_is_open,
 4873                cx,
 4874            )
 4875        } else {
 4876            false
 4877        }
 4878    }
 4879
 4880    /// If any empty selections is touching the start of its innermost containing autoclose
 4881    /// region, expand it to select the brackets.
 4882    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4883        let selections = self.selections.all::<usize>(cx);
 4884        let buffer = self.buffer.read(cx).read(cx);
 4885        let new_selections = self
 4886            .selections_with_autoclose_regions(selections, &buffer)
 4887            .map(|(mut selection, region)| {
 4888                if !selection.is_empty() {
 4889                    return selection;
 4890                }
 4891
 4892                if let Some(region) = region {
 4893                    let mut range = region.range.to_offset(&buffer);
 4894                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4895                        range.start -= region.pair.start.len();
 4896                        if buffer.contains_str_at(range.start, &region.pair.start)
 4897                            && buffer.contains_str_at(range.end, &region.pair.end)
 4898                        {
 4899                            range.end += region.pair.end.len();
 4900                            selection.start = range.start;
 4901                            selection.end = range.end;
 4902
 4903                            return selection;
 4904                        }
 4905                    }
 4906                }
 4907
 4908                let always_treat_brackets_as_autoclosed = buffer
 4909                    .language_settings_at(selection.start, cx)
 4910                    .always_treat_brackets_as_autoclosed;
 4911
 4912                if !always_treat_brackets_as_autoclosed {
 4913                    return selection;
 4914                }
 4915
 4916                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4917                    for (pair, enabled) in scope.brackets() {
 4918                        if !enabled || !pair.close {
 4919                            continue;
 4920                        }
 4921
 4922                        if buffer.contains_str_at(selection.start, &pair.end) {
 4923                            let pair_start_len = pair.start.len();
 4924                            if buffer.contains_str_at(
 4925                                selection.start.saturating_sub(pair_start_len),
 4926                                &pair.start,
 4927                            ) {
 4928                                selection.start -= pair_start_len;
 4929                                selection.end += pair.end.len();
 4930
 4931                                return selection;
 4932                            }
 4933                        }
 4934                    }
 4935                }
 4936
 4937                selection
 4938            })
 4939            .collect();
 4940
 4941        drop(buffer);
 4942        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4943            selections.select(new_selections)
 4944        });
 4945    }
 4946
 4947    /// Iterate the given selections, and for each one, find the smallest surrounding
 4948    /// autoclose region. This uses the ordering of the selections and the autoclose
 4949    /// regions to avoid repeated comparisons.
 4950    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4951        &'a self,
 4952        selections: impl IntoIterator<Item = Selection<D>>,
 4953        buffer: &'a MultiBufferSnapshot,
 4954    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4955        let mut i = 0;
 4956        let mut regions = self.autoclose_regions.as_slice();
 4957        selections.into_iter().map(move |selection| {
 4958            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4959
 4960            let mut enclosing = None;
 4961            while let Some(pair_state) = regions.get(i) {
 4962                if pair_state.range.end.to_offset(buffer) < range.start {
 4963                    regions = &regions[i + 1..];
 4964                    i = 0;
 4965                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4966                    break;
 4967                } else {
 4968                    if pair_state.selection_id == selection.id {
 4969                        enclosing = Some(pair_state);
 4970                    }
 4971                    i += 1;
 4972                }
 4973            }
 4974
 4975            (selection, enclosing)
 4976        })
 4977    }
 4978
 4979    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4980    fn invalidate_autoclose_regions(
 4981        &mut self,
 4982        mut selections: &[Selection<Anchor>],
 4983        buffer: &MultiBufferSnapshot,
 4984    ) {
 4985        self.autoclose_regions.retain(|state| {
 4986            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4987                return false;
 4988            }
 4989
 4990            let mut i = 0;
 4991            while let Some(selection) = selections.get(i) {
 4992                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4993                    selections = &selections[1..];
 4994                    continue;
 4995                }
 4996                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4997                    break;
 4998                }
 4999                if selection.id == state.selection_id {
 5000                    return true;
 5001                } else {
 5002                    i += 1;
 5003                }
 5004            }
 5005            false
 5006        });
 5007    }
 5008
 5009    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5010        let offset = position.to_offset(buffer);
 5011        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5012        if offset > word_range.start && kind == Some(CharKind::Word) {
 5013            Some(
 5014                buffer
 5015                    .text_for_range(word_range.start..offset)
 5016                    .collect::<String>(),
 5017            )
 5018        } else {
 5019            None
 5020        }
 5021    }
 5022
 5023    pub fn toggle_inline_values(
 5024        &mut self,
 5025        _: &ToggleInlineValues,
 5026        _: &mut Window,
 5027        cx: &mut Context<Self>,
 5028    ) {
 5029        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5030
 5031        self.refresh_inline_values(cx);
 5032    }
 5033
 5034    pub fn toggle_inlay_hints(
 5035        &mut self,
 5036        _: &ToggleInlayHints,
 5037        _: &mut Window,
 5038        cx: &mut Context<Self>,
 5039    ) {
 5040        self.refresh_inlay_hints(
 5041            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5042            cx,
 5043        );
 5044    }
 5045
 5046    pub fn inlay_hints_enabled(&self) -> bool {
 5047        self.inlay_hint_cache.enabled
 5048    }
 5049
 5050    pub fn inline_values_enabled(&self) -> bool {
 5051        self.inline_value_cache.enabled
 5052    }
 5053
 5054    #[cfg(any(test, feature = "test-support"))]
 5055    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5056        self.display_map
 5057            .read(cx)
 5058            .current_inlays()
 5059            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5060            .cloned()
 5061            .collect()
 5062    }
 5063
 5064    #[cfg(any(test, feature = "test-support"))]
 5065    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5066        self.display_map
 5067            .read(cx)
 5068            .current_inlays()
 5069            .cloned()
 5070            .collect()
 5071    }
 5072
 5073    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5074        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5075            return;
 5076        }
 5077
 5078        let reason_description = reason.description();
 5079        let ignore_debounce = matches!(
 5080            reason,
 5081            InlayHintRefreshReason::SettingsChange(_)
 5082                | InlayHintRefreshReason::Toggle(_)
 5083                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5084                | InlayHintRefreshReason::ModifiersChanged(_)
 5085        );
 5086        let (invalidate_cache, required_languages) = match reason {
 5087            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5088                match self.inlay_hint_cache.modifiers_override(enabled) {
 5089                    Some(enabled) => {
 5090                        if enabled {
 5091                            (InvalidationStrategy::RefreshRequested, None)
 5092                        } else {
 5093                            self.splice_inlays(
 5094                                &self
 5095                                    .visible_inlay_hints(cx)
 5096                                    .iter()
 5097                                    .map(|inlay| inlay.id)
 5098                                    .collect::<Vec<InlayId>>(),
 5099                                Vec::new(),
 5100                                cx,
 5101                            );
 5102                            return;
 5103                        }
 5104                    }
 5105                    None => return,
 5106                }
 5107            }
 5108            InlayHintRefreshReason::Toggle(enabled) => {
 5109                if self.inlay_hint_cache.toggle(enabled) {
 5110                    if enabled {
 5111                        (InvalidationStrategy::RefreshRequested, None)
 5112                    } else {
 5113                        self.splice_inlays(
 5114                            &self
 5115                                .visible_inlay_hints(cx)
 5116                                .iter()
 5117                                .map(|inlay| inlay.id)
 5118                                .collect::<Vec<InlayId>>(),
 5119                            Vec::new(),
 5120                            cx,
 5121                        );
 5122                        return;
 5123                    }
 5124                } else {
 5125                    return;
 5126                }
 5127            }
 5128            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5129                match self.inlay_hint_cache.update_settings(
 5130                    &self.buffer,
 5131                    new_settings,
 5132                    self.visible_inlay_hints(cx),
 5133                    cx,
 5134                ) {
 5135                    ControlFlow::Break(Some(InlaySplice {
 5136                        to_remove,
 5137                        to_insert,
 5138                    })) => {
 5139                        self.splice_inlays(&to_remove, to_insert, cx);
 5140                        return;
 5141                    }
 5142                    ControlFlow::Break(None) => return,
 5143                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5144                }
 5145            }
 5146            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5147                if let Some(InlaySplice {
 5148                    to_remove,
 5149                    to_insert,
 5150                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5151                {
 5152                    self.splice_inlays(&to_remove, to_insert, cx);
 5153                }
 5154                self.display_map.update(cx, |display_map, _| {
 5155                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5156                });
 5157                return;
 5158            }
 5159            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5160            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5161                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5162            }
 5163            InlayHintRefreshReason::RefreshRequested => {
 5164                (InvalidationStrategy::RefreshRequested, None)
 5165            }
 5166        };
 5167
 5168        if let Some(InlaySplice {
 5169            to_remove,
 5170            to_insert,
 5171        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5172            reason_description,
 5173            self.visible_excerpts(required_languages.as_ref(), cx),
 5174            invalidate_cache,
 5175            ignore_debounce,
 5176            cx,
 5177        ) {
 5178            self.splice_inlays(&to_remove, to_insert, cx);
 5179        }
 5180    }
 5181
 5182    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5183        self.display_map
 5184            .read(cx)
 5185            .current_inlays()
 5186            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    pub fn visible_excerpts(
 5192        &self,
 5193        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5194        cx: &mut Context<Editor>,
 5195    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5196        let Some(project) = self.project.as_ref() else {
 5197            return HashMap::default();
 5198        };
 5199        let project = project.read(cx);
 5200        let multi_buffer = self.buffer().read(cx);
 5201        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5202        let multi_buffer_visible_start = self
 5203            .scroll_manager
 5204            .anchor()
 5205            .anchor
 5206            .to_point(&multi_buffer_snapshot);
 5207        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5208            multi_buffer_visible_start
 5209                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5210            Bias::Left,
 5211        );
 5212        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5213        multi_buffer_snapshot
 5214            .range_to_buffer_ranges(multi_buffer_visible_range)
 5215            .into_iter()
 5216            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5217            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5218                let buffer_file = project::File::from_dyn(buffer.file())?;
 5219                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5220                let worktree_entry = buffer_worktree
 5221                    .read(cx)
 5222                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5223                if worktree_entry.is_ignored {
 5224                    return None;
 5225                }
 5226
 5227                let language = buffer.language()?;
 5228                if let Some(restrict_to_languages) = restrict_to_languages {
 5229                    if !restrict_to_languages.contains(language) {
 5230                        return None;
 5231                    }
 5232                }
 5233                Some((
 5234                    excerpt_id,
 5235                    (
 5236                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5237                        buffer.version().clone(),
 5238                        excerpt_visible_range,
 5239                    ),
 5240                ))
 5241            })
 5242            .collect()
 5243    }
 5244
 5245    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5246        TextLayoutDetails {
 5247            text_system: window.text_system().clone(),
 5248            editor_style: self.style.clone().unwrap(),
 5249            rem_size: window.rem_size(),
 5250            scroll_anchor: self.scroll_manager.anchor(),
 5251            visible_rows: self.visible_line_count(),
 5252            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5253        }
 5254    }
 5255
 5256    pub fn splice_inlays(
 5257        &self,
 5258        to_remove: &[InlayId],
 5259        to_insert: Vec<Inlay>,
 5260        cx: &mut Context<Self>,
 5261    ) {
 5262        self.display_map.update(cx, |display_map, cx| {
 5263            display_map.splice_inlays(to_remove, to_insert, cx)
 5264        });
 5265        cx.notify();
 5266    }
 5267
 5268    fn trigger_on_type_formatting(
 5269        &self,
 5270        input: String,
 5271        window: &mut Window,
 5272        cx: &mut Context<Self>,
 5273    ) -> Option<Task<Result<()>>> {
 5274        if input.len() != 1 {
 5275            return None;
 5276        }
 5277
 5278        let project = self.project.as_ref()?;
 5279        let position = self.selections.newest_anchor().head();
 5280        let (buffer, buffer_position) = self
 5281            .buffer
 5282            .read(cx)
 5283            .text_anchor_for_position(position, cx)?;
 5284
 5285        let settings = language_settings::language_settings(
 5286            buffer
 5287                .read(cx)
 5288                .language_at(buffer_position)
 5289                .map(|l| l.name()),
 5290            buffer.read(cx).file(),
 5291            cx,
 5292        );
 5293        if !settings.use_on_type_format {
 5294            return None;
 5295        }
 5296
 5297        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5298        // hence we do LSP request & edit on host side only — add formats to host's history.
 5299        let push_to_lsp_host_history = true;
 5300        // If this is not the host, append its history with new edits.
 5301        let push_to_client_history = project.read(cx).is_via_collab();
 5302
 5303        let on_type_formatting = project.update(cx, |project, cx| {
 5304            project.on_type_format(
 5305                buffer.clone(),
 5306                buffer_position,
 5307                input,
 5308                push_to_lsp_host_history,
 5309                cx,
 5310            )
 5311        });
 5312        Some(cx.spawn_in(window, async move |editor, cx| {
 5313            if let Some(transaction) = on_type_formatting.await? {
 5314                if push_to_client_history {
 5315                    buffer
 5316                        .update(cx, |buffer, _| {
 5317                            buffer.push_transaction(transaction, Instant::now());
 5318                            buffer.finalize_last_transaction();
 5319                        })
 5320                        .ok();
 5321                }
 5322                editor.update(cx, |editor, cx| {
 5323                    editor.refresh_document_highlights(cx);
 5324                })?;
 5325            }
 5326            Ok(())
 5327        }))
 5328    }
 5329
 5330    pub fn show_word_completions(
 5331        &mut self,
 5332        _: &ShowWordCompletions,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5337    }
 5338
 5339    pub fn show_completions(
 5340        &mut self,
 5341        options: &ShowCompletions,
 5342        window: &mut Window,
 5343        cx: &mut Context<Self>,
 5344    ) {
 5345        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5346    }
 5347
 5348    fn open_or_update_completions_menu(
 5349        &mut self,
 5350        requested_source: Option<CompletionsMenuSource>,
 5351        trigger: Option<&str>,
 5352        window: &mut Window,
 5353        cx: &mut Context<Self>,
 5354    ) {
 5355        if self.pending_rename.is_some() {
 5356            return;
 5357        }
 5358
 5359        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5360
 5361        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5362        // inserted and selected. To handle that case, the start of the selection is used so that
 5363        // the menu starts with all choices.
 5364        let position = self
 5365            .selections
 5366            .newest_anchor()
 5367            .start
 5368            .bias_right(&multibuffer_snapshot);
 5369        if position.diff_base_anchor.is_some() {
 5370            return;
 5371        }
 5372        let (buffer, buffer_position) =
 5373            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5374                output
 5375            } else {
 5376                return;
 5377            };
 5378        let buffer_snapshot = buffer.read(cx).snapshot();
 5379
 5380        let query: Option<Arc<String>> =
 5381            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5382
 5383        drop(multibuffer_snapshot);
 5384
 5385        let provider = match requested_source {
 5386            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5387            Some(CompletionsMenuSource::Words) => None,
 5388            Some(CompletionsMenuSource::SnippetChoices) => {
 5389                log::error!("bug: SnippetChoices requested_source is not handled");
 5390                None
 5391            }
 5392        };
 5393
 5394        let sort_completions = provider
 5395            .as_ref()
 5396            .map_or(false, |provider| provider.sort_completions());
 5397
 5398        let filter_completions = provider
 5399            .as_ref()
 5400            .map_or(true, |provider| provider.filter_completions());
 5401
 5402        let trigger_kind = match trigger {
 5403            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5404                CompletionTriggerKind::TRIGGER_CHARACTER
 5405            }
 5406            _ => CompletionTriggerKind::INVOKED,
 5407        };
 5408        let completion_context = CompletionContext {
 5409            trigger_character: trigger.and_then(|trigger| {
 5410                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5411                    Some(String::from(trigger))
 5412                } else {
 5413                    None
 5414                }
 5415            }),
 5416            trigger_kind,
 5417        };
 5418
 5419        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5420        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5421        // involve trigger chars, so this is skipped in that case.
 5422        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5423        {
 5424            let menu_is_open = matches!(
 5425                self.context_menu.borrow().as_ref(),
 5426                Some(CodeContextMenu::Completions(_))
 5427            );
 5428            if menu_is_open {
 5429                self.hide_context_menu(window, cx);
 5430            }
 5431        }
 5432
 5433        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5434            if filter_completions {
 5435                menu.filter(query.clone(), provider.clone(), window, cx);
 5436            }
 5437            // When `is_incomplete` is false, no need to re-query completions when the current query
 5438            // is a suffix of the initial query.
 5439            if !menu.is_incomplete {
 5440                // If the new query is a suffix of the old query (typing more characters) and
 5441                // the previous result was complete, the existing completions can be filtered.
 5442                //
 5443                // Note that this is always true for snippet completions.
 5444                let query_matches = match (&menu.initial_query, &query) {
 5445                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5446                    (None, _) => true,
 5447                    _ => false,
 5448                };
 5449                if query_matches {
 5450                    let position_matches = if menu.initial_position == position {
 5451                        true
 5452                    } else {
 5453                        let snapshot = self.buffer.read(cx).read(cx);
 5454                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5455                    };
 5456                    if position_matches {
 5457                        return;
 5458                    }
 5459                }
 5460            }
 5461        };
 5462
 5463        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5464            buffer_snapshot.surrounding_word(buffer_position, false)
 5465        {
 5466            let word_to_exclude = buffer_snapshot
 5467                .text_for_range(word_range.clone())
 5468                .collect::<String>();
 5469            (
 5470                buffer_snapshot.anchor_before(word_range.start)
 5471                    ..buffer_snapshot.anchor_after(buffer_position),
 5472                Some(word_to_exclude),
 5473            )
 5474        } else {
 5475            (buffer_position..buffer_position, None)
 5476        };
 5477
 5478        let language = buffer_snapshot
 5479            .language_at(buffer_position)
 5480            .map(|language| language.name());
 5481
 5482        let completion_settings =
 5483            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5484
 5485        let show_completion_documentation = buffer_snapshot
 5486            .settings_at(buffer_position, cx)
 5487            .show_completion_documentation;
 5488
 5489        // The document can be large, so stay in reasonable bounds when searching for words,
 5490        // otherwise completion pop-up might be slow to appear.
 5491        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5492        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5493        let min_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5495            Bias::Left,
 5496        );
 5497        let max_word_search = buffer_snapshot.clip_point(
 5498            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5499            Bias::Right,
 5500        );
 5501        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5502            ..buffer_snapshot.point_to_offset(max_word_search);
 5503
 5504        let skip_digits = query
 5505            .as_ref()
 5506            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5507
 5508        let (mut words, provider_responses) = match &provider {
 5509            Some(provider) => {
 5510                let provider_responses = provider.completions(
 5511                    position.excerpt_id,
 5512                    &buffer,
 5513                    buffer_position,
 5514                    completion_context,
 5515                    window,
 5516                    cx,
 5517                );
 5518
 5519                let words = match completion_settings.words {
 5520                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5521                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5522                        .background_spawn(async move {
 5523                            buffer_snapshot.words_in_range(WordsQuery {
 5524                                fuzzy_contents: None,
 5525                                range: word_search_range,
 5526                                skip_digits,
 5527                            })
 5528                        }),
 5529                };
 5530
 5531                (words, provider_responses)
 5532            }
 5533            None => (
 5534                cx.background_spawn(async move {
 5535                    buffer_snapshot.words_in_range(WordsQuery {
 5536                        fuzzy_contents: None,
 5537                        range: word_search_range,
 5538                        skip_digits,
 5539                    })
 5540                }),
 5541                Task::ready(Ok(Vec::new())),
 5542            ),
 5543        };
 5544
 5545        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5546
 5547        let id = post_inc(&mut self.next_completion_id);
 5548        let task = cx.spawn_in(window, async move |editor, cx| {
 5549            let Ok(()) = editor.update(cx, |this, _| {
 5550                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5551            }) else {
 5552                return;
 5553            };
 5554
 5555            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5556            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5557            let mut completions = Vec::new();
 5558            let mut is_incomplete = false;
 5559            if let Some(provider_responses) = provider_responses.await.log_err() {
 5560                if !provider_responses.is_empty() {
 5561                    for response in provider_responses {
 5562                        completions.extend(response.completions);
 5563                        is_incomplete = is_incomplete || response.is_incomplete;
 5564                    }
 5565                    if completion_settings.words == WordsCompletionMode::Fallback {
 5566                        words = Task::ready(BTreeMap::default());
 5567                    }
 5568                }
 5569            }
 5570
 5571            let mut words = words.await;
 5572            if let Some(word_to_exclude) = &word_to_exclude {
 5573                words.remove(word_to_exclude);
 5574            }
 5575            for lsp_completion in &completions {
 5576                words.remove(&lsp_completion.new_text);
 5577            }
 5578            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5579                replace_range: word_replace_range.clone(),
 5580                new_text: word.clone(),
 5581                label: CodeLabel::plain(word, None),
 5582                icon_path: None,
 5583                documentation: None,
 5584                source: CompletionSource::BufferWord {
 5585                    word_range,
 5586                    resolved: false,
 5587                },
 5588                insert_text_mode: Some(InsertTextMode::AS_IS),
 5589                confirm: None,
 5590            }));
 5591
 5592            let menu = if completions.is_empty() {
 5593                None
 5594            } else {
 5595                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5596                    let languages = editor
 5597                        .workspace
 5598                        .as_ref()
 5599                        .and_then(|(workspace, _)| workspace.upgrade())
 5600                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5601                    let menu = CompletionsMenu::new(
 5602                        id,
 5603                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5604                        sort_completions,
 5605                        show_completion_documentation,
 5606                        position,
 5607                        query.clone(),
 5608                        is_incomplete,
 5609                        buffer.clone(),
 5610                        completions.into(),
 5611                        snippet_sort_order,
 5612                        languages,
 5613                        language,
 5614                        cx,
 5615                    );
 5616
 5617                    let query = if filter_completions { query } else { None };
 5618                    let matches_task = if let Some(query) = query {
 5619                        menu.do_async_filtering(query, cx)
 5620                    } else {
 5621                        Task::ready(menu.unfiltered_matches())
 5622                    };
 5623                    (menu, matches_task)
 5624                }) else {
 5625                    return;
 5626                };
 5627
 5628                let matches = matches_task.await;
 5629
 5630                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5631                    // Newer menu already set, so exit.
 5632                    match editor.context_menu.borrow().as_ref() {
 5633                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5634                            if prev_menu.id > id {
 5635                                return;
 5636                            }
 5637                        }
 5638                        _ => {}
 5639                    };
 5640
 5641                    // Only valid to take prev_menu because it the new menu is immediately set
 5642                    // below, or the menu is hidden.
 5643                    match editor.context_menu.borrow_mut().take() {
 5644                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5645                            let position_matches =
 5646                                if prev_menu.initial_position == menu.initial_position {
 5647                                    true
 5648                                } else {
 5649                                    let snapshot = editor.buffer.read(cx).read(cx);
 5650                                    prev_menu.initial_position.to_offset(&snapshot)
 5651                                        == menu.initial_position.to_offset(&snapshot)
 5652                                };
 5653                            if position_matches {
 5654                                // Preserve markdown cache before `set_filter_results` because it will
 5655                                // try to populate the documentation cache.
 5656                                menu.preserve_markdown_cache(prev_menu);
 5657                            }
 5658                        }
 5659                        _ => {}
 5660                    };
 5661
 5662                    menu.set_filter_results(matches, provider, window, cx);
 5663                }) else {
 5664                    return;
 5665                };
 5666
 5667                menu.visible().then_some(menu)
 5668            };
 5669
 5670            editor
 5671                .update_in(cx, |editor, window, cx| {
 5672                    if editor.focus_handle.is_focused(window) {
 5673                        if let Some(menu) = menu {
 5674                            *editor.context_menu.borrow_mut() =
 5675                                Some(CodeContextMenu::Completions(menu));
 5676
 5677                            crate::hover_popover::hide_hover(editor, cx);
 5678                            if editor.show_edit_predictions_in_menu() {
 5679                                editor.update_visible_inline_completion(window, cx);
 5680                            } else {
 5681                                editor.discard_inline_completion(false, cx);
 5682                            }
 5683
 5684                            cx.notify();
 5685                            return;
 5686                        }
 5687                    }
 5688
 5689                    if editor.completion_tasks.len() <= 1 {
 5690                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5691                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5692                        // If it was already hidden and we don't show inline completions in the menu, we should
 5693                        // also show the inline-completion when available.
 5694                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5695                            editor.update_visible_inline_completion(window, cx);
 5696                        }
 5697                    }
 5698                })
 5699                .ok();
 5700        });
 5701
 5702        self.completion_tasks.push((id, task));
 5703    }
 5704
 5705    #[cfg(feature = "test-support")]
 5706    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5707        let menu = self.context_menu.borrow();
 5708        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5709            let completions = menu.completions.borrow();
 5710            Some(completions.to_vec())
 5711        } else {
 5712            None
 5713        }
 5714    }
 5715
 5716    pub fn with_completions_menu_matching_id<R>(
 5717        &self,
 5718        id: CompletionId,
 5719        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5720    ) -> R {
 5721        let mut context_menu = self.context_menu.borrow_mut();
 5722        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5723            return f(None);
 5724        };
 5725        if completions_menu.id != id {
 5726            return f(None);
 5727        }
 5728        f(Some(completions_menu))
 5729    }
 5730
 5731    pub fn confirm_completion(
 5732        &mut self,
 5733        action: &ConfirmCompletion,
 5734        window: &mut Window,
 5735        cx: &mut Context<Self>,
 5736    ) -> Option<Task<Result<()>>> {
 5737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5738        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5739    }
 5740
 5741    pub fn confirm_completion_insert(
 5742        &mut self,
 5743        _: &ConfirmCompletionInsert,
 5744        window: &mut Window,
 5745        cx: &mut Context<Self>,
 5746    ) -> Option<Task<Result<()>>> {
 5747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5748        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5749    }
 5750
 5751    pub fn confirm_completion_replace(
 5752        &mut self,
 5753        _: &ConfirmCompletionReplace,
 5754        window: &mut Window,
 5755        cx: &mut Context<Self>,
 5756    ) -> Option<Task<Result<()>>> {
 5757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5758        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5759    }
 5760
 5761    pub fn compose_completion(
 5762        &mut self,
 5763        action: &ComposeCompletion,
 5764        window: &mut Window,
 5765        cx: &mut Context<Self>,
 5766    ) -> Option<Task<Result<()>>> {
 5767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5768        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5769    }
 5770
 5771    fn do_completion(
 5772        &mut self,
 5773        item_ix: Option<usize>,
 5774        intent: CompletionIntent,
 5775        window: &mut Window,
 5776        cx: &mut Context<Editor>,
 5777    ) -> Option<Task<Result<()>>> {
 5778        use language::ToOffset as _;
 5779
 5780        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5781        else {
 5782            return None;
 5783        };
 5784
 5785        let candidate_id = {
 5786            let entries = completions_menu.entries.borrow();
 5787            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5788            if self.show_edit_predictions_in_menu() {
 5789                self.discard_inline_completion(true, cx);
 5790            }
 5791            mat.candidate_id
 5792        };
 5793
 5794        let completion = completions_menu
 5795            .completions
 5796            .borrow()
 5797            .get(candidate_id)?
 5798            .clone();
 5799        cx.stop_propagation();
 5800
 5801        let buffer_handle = completions_menu.buffer.clone();
 5802
 5803        let CompletionEdit {
 5804            new_text,
 5805            snippet,
 5806            replace_range,
 5807        } = process_completion_for_edit(
 5808            &completion,
 5809            intent,
 5810            &buffer_handle,
 5811            &completions_menu.initial_position.text_anchor,
 5812            cx,
 5813        );
 5814
 5815        let buffer = buffer_handle.read(cx);
 5816        let snapshot = self.buffer.read(cx).snapshot(cx);
 5817        let newest_anchor = self.selections.newest_anchor();
 5818        let replace_range_multibuffer = {
 5819            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5820            let multibuffer_anchor = snapshot
 5821                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5822                .unwrap()
 5823                ..snapshot
 5824                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5825                    .unwrap();
 5826            multibuffer_anchor.start.to_offset(&snapshot)
 5827                ..multibuffer_anchor.end.to_offset(&snapshot)
 5828        };
 5829        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5830            return None;
 5831        }
 5832
 5833        let old_text = buffer
 5834            .text_for_range(replace_range.clone())
 5835            .collect::<String>();
 5836        let lookbehind = newest_anchor
 5837            .start
 5838            .text_anchor
 5839            .to_offset(buffer)
 5840            .saturating_sub(replace_range.start);
 5841        let lookahead = replace_range
 5842            .end
 5843            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5844        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5845        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5846
 5847        let selections = self.selections.all::<usize>(cx);
 5848        let mut ranges = Vec::new();
 5849        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5850
 5851        for selection in &selections {
 5852            let range = if selection.id == newest_anchor.id {
 5853                replace_range_multibuffer.clone()
 5854            } else {
 5855                let mut range = selection.range();
 5856
 5857                // if prefix is present, don't duplicate it
 5858                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5859                    range.start = range.start.saturating_sub(lookbehind);
 5860
 5861                    // if suffix is also present, mimic the newest cursor and replace it
 5862                    if selection.id != newest_anchor.id
 5863                        && snapshot.contains_str_at(range.end, suffix)
 5864                    {
 5865                        range.end += lookahead;
 5866                    }
 5867                }
 5868                range
 5869            };
 5870
 5871            ranges.push(range.clone());
 5872
 5873            if !self.linked_edit_ranges.is_empty() {
 5874                let start_anchor = snapshot.anchor_before(range.start);
 5875                let end_anchor = snapshot.anchor_after(range.end);
 5876                if let Some(ranges) = self
 5877                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5878                {
 5879                    for (buffer, edits) in ranges {
 5880                        linked_edits
 5881                            .entry(buffer.clone())
 5882                            .or_default()
 5883                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5884                    }
 5885                }
 5886            }
 5887        }
 5888
 5889        let common_prefix_len = old_text
 5890            .chars()
 5891            .zip(new_text.chars())
 5892            .take_while(|(a, b)| a == b)
 5893            .map(|(a, _)| a.len_utf8())
 5894            .sum::<usize>();
 5895
 5896        cx.emit(EditorEvent::InputHandled {
 5897            utf16_range_to_replace: None,
 5898            text: new_text[common_prefix_len..].into(),
 5899        });
 5900
 5901        self.transact(window, cx, |editor, window, cx| {
 5902            if let Some(mut snippet) = snippet {
 5903                snippet.text = new_text.to_string();
 5904                editor
 5905                    .insert_snippet(&ranges, snippet, window, cx)
 5906                    .log_err();
 5907            } else {
 5908                editor.buffer.update(cx, |multi_buffer, cx| {
 5909                    let auto_indent = match completion.insert_text_mode {
 5910                        Some(InsertTextMode::AS_IS) => None,
 5911                        _ => editor.autoindent_mode.clone(),
 5912                    };
 5913                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5914                    multi_buffer.edit(edits, auto_indent, cx);
 5915                });
 5916            }
 5917            for (buffer, edits) in linked_edits {
 5918                buffer.update(cx, |buffer, cx| {
 5919                    let snapshot = buffer.snapshot();
 5920                    let edits = edits
 5921                        .into_iter()
 5922                        .map(|(range, text)| {
 5923                            use text::ToPoint as TP;
 5924                            let end_point = TP::to_point(&range.end, &snapshot);
 5925                            let start_point = TP::to_point(&range.start, &snapshot);
 5926                            (start_point..end_point, text)
 5927                        })
 5928                        .sorted_by_key(|(range, _)| range.start);
 5929                    buffer.edit(edits, None, cx);
 5930                })
 5931            }
 5932
 5933            editor.refresh_inline_completion(true, false, window, cx);
 5934        });
 5935        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5936
 5937        let show_new_completions_on_confirm = completion
 5938            .confirm
 5939            .as_ref()
 5940            .map_or(false, |confirm| confirm(intent, window, cx));
 5941        if show_new_completions_on_confirm {
 5942            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5943        }
 5944
 5945        let provider = self.completion_provider.as_ref()?;
 5946        drop(completion);
 5947        let apply_edits = provider.apply_additional_edits_for_completion(
 5948            buffer_handle,
 5949            completions_menu.completions.clone(),
 5950            candidate_id,
 5951            true,
 5952            cx,
 5953        );
 5954
 5955        let editor_settings = EditorSettings::get_global(cx);
 5956        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5957            // After the code completion is finished, users often want to know what signatures are needed.
 5958            // so we should automatically call signature_help
 5959            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5960        }
 5961
 5962        Some(cx.foreground_executor().spawn(async move {
 5963            apply_edits.await?;
 5964            Ok(())
 5965        }))
 5966    }
 5967
 5968    pub fn toggle_code_actions(
 5969        &mut self,
 5970        action: &ToggleCodeActions,
 5971        window: &mut Window,
 5972        cx: &mut Context<Self>,
 5973    ) {
 5974        let quick_launch = action.quick_launch;
 5975        let mut context_menu = self.context_menu.borrow_mut();
 5976        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5977            if code_actions.deployed_from == action.deployed_from {
 5978                // Toggle if we're selecting the same one
 5979                *context_menu = None;
 5980                cx.notify();
 5981                return;
 5982            } else {
 5983                // Otherwise, clear it and start a new one
 5984                *context_menu = None;
 5985                cx.notify();
 5986            }
 5987        }
 5988        drop(context_menu);
 5989        let snapshot = self.snapshot(window, cx);
 5990        let deployed_from = action.deployed_from.clone();
 5991        let action = action.clone();
 5992        self.completion_tasks.clear();
 5993        self.discard_inline_completion(false, cx);
 5994
 5995        let multibuffer_point = match &action.deployed_from {
 5996            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5997                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5998            }
 5999            _ => self.selections.newest::<Point>(cx).head(),
 6000        };
 6001        let Some((buffer, buffer_row)) = snapshot
 6002            .buffer_snapshot
 6003            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6004            .and_then(|(buffer_snapshot, range)| {
 6005                self.buffer()
 6006                    .read(cx)
 6007                    .buffer(buffer_snapshot.remote_id())
 6008                    .map(|buffer| (buffer, range.start.row))
 6009            })
 6010        else {
 6011            return;
 6012        };
 6013        let buffer_id = buffer.read(cx).remote_id();
 6014        let tasks = self
 6015            .tasks
 6016            .get(&(buffer_id, buffer_row))
 6017            .map(|t| Arc::new(t.to_owned()));
 6018
 6019        if !self.focus_handle.is_focused(window) {
 6020            return;
 6021        }
 6022        let project = self.project.clone();
 6023
 6024        let code_actions_task = match deployed_from {
 6025            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6026            _ => self.code_actions(buffer_row, window, cx),
 6027        };
 6028
 6029        let runnable_task = match deployed_from {
 6030            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6031            _ => {
 6032                let mut task_context_task = Task::ready(None);
 6033                if let Some(tasks) = &tasks {
 6034                    if let Some(project) = project {
 6035                        task_context_task =
 6036                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6037                    }
 6038                }
 6039
 6040                cx.spawn_in(window, {
 6041                    let buffer = buffer.clone();
 6042                    async move |editor, cx| {
 6043                        let task_context = task_context_task.await;
 6044
 6045                        let resolved_tasks =
 6046                            tasks
 6047                                .zip(task_context.clone())
 6048                                .map(|(tasks, task_context)| ResolvedTasks {
 6049                                    templates: tasks.resolve(&task_context).collect(),
 6050                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6051                                        multibuffer_point.row,
 6052                                        tasks.column,
 6053                                    )),
 6054                                });
 6055                        let debug_scenarios = editor
 6056                            .update(cx, |editor, cx| {
 6057                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6058                            })?
 6059                            .await;
 6060                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6061                    }
 6062                })
 6063            }
 6064        };
 6065
 6066        cx.spawn_in(window, async move |editor, cx| {
 6067            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6068            let code_actions = code_actions_task.await;
 6069            let spawn_straight_away = quick_launch
 6070                && resolved_tasks
 6071                    .as_ref()
 6072                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6073                && code_actions
 6074                    .as_ref()
 6075                    .map_or(true, |actions| actions.is_empty())
 6076                && debug_scenarios.is_empty();
 6077
 6078            editor.update_in(cx, |editor, window, cx| {
 6079                crate::hover_popover::hide_hover(editor, cx);
 6080                let actions = CodeActionContents::new(
 6081                    resolved_tasks,
 6082                    code_actions,
 6083                    debug_scenarios,
 6084                    task_context.unwrap_or_default(),
 6085                );
 6086
 6087                // Don't show the menu if there are no actions available
 6088                if actions.is_empty() {
 6089                    cx.notify();
 6090                    return Task::ready(Ok(()));
 6091                }
 6092
 6093                *editor.context_menu.borrow_mut() =
 6094                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6095                        buffer,
 6096                        actions,
 6097                        selected_item: Default::default(),
 6098                        scroll_handle: UniformListScrollHandle::default(),
 6099                        deployed_from,
 6100                    }));
 6101                cx.notify();
 6102                if spawn_straight_away {
 6103                    if let Some(task) = editor.confirm_code_action(
 6104                        &ConfirmCodeAction { item_ix: Some(0) },
 6105                        window,
 6106                        cx,
 6107                    ) {
 6108                        return task;
 6109                    }
 6110                }
 6111
 6112                Task::ready(Ok(()))
 6113            })
 6114        })
 6115        .detach_and_log_err(cx);
 6116    }
 6117
 6118    fn debug_scenarios(
 6119        &mut self,
 6120        resolved_tasks: &Option<ResolvedTasks>,
 6121        buffer: &Entity<Buffer>,
 6122        cx: &mut App,
 6123    ) -> Task<Vec<task::DebugScenario>> {
 6124        maybe!({
 6125            let project = self.project.as_ref()?;
 6126            let dap_store = project.read(cx).dap_store();
 6127            let mut scenarios = vec![];
 6128            let resolved_tasks = resolved_tasks.as_ref()?;
 6129            let buffer = buffer.read(cx);
 6130            let language = buffer.language()?;
 6131            let file = buffer.file();
 6132            let debug_adapter = language_settings(language.name().into(), file, cx)
 6133                .debuggers
 6134                .first()
 6135                .map(SharedString::from)
 6136                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6137
 6138            dap_store.update(cx, |dap_store, cx| {
 6139                for (_, task) in &resolved_tasks.templates {
 6140                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6141                        task.original_task().clone(),
 6142                        debug_adapter.clone().into(),
 6143                        task.display_label().to_owned().into(),
 6144                        cx,
 6145                    );
 6146                    scenarios.push(maybe_scenario);
 6147                }
 6148            });
 6149            Some(cx.background_spawn(async move {
 6150                let scenarios = futures::future::join_all(scenarios)
 6151                    .await
 6152                    .into_iter()
 6153                    .flatten()
 6154                    .collect::<Vec<_>>();
 6155                scenarios
 6156            }))
 6157        })
 6158        .unwrap_or_else(|| Task::ready(vec![]))
 6159    }
 6160
 6161    fn code_actions(
 6162        &mut self,
 6163        buffer_row: u32,
 6164        window: &mut Window,
 6165        cx: &mut Context<Self>,
 6166    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6167        let mut task = self.code_actions_task.take();
 6168        cx.spawn_in(window, async move |editor, cx| {
 6169            while let Some(prev_task) = task {
 6170                prev_task.await.log_err();
 6171                task = editor
 6172                    .update(cx, |this, _| this.code_actions_task.take())
 6173                    .ok()?;
 6174            }
 6175
 6176            editor
 6177                .update(cx, |editor, cx| {
 6178                    editor
 6179                        .available_code_actions
 6180                        .clone()
 6181                        .and_then(|(location, code_actions)| {
 6182                            let snapshot = location.buffer.read(cx).snapshot();
 6183                            let point_range = location.range.to_point(&snapshot);
 6184                            let point_range = point_range.start.row..=point_range.end.row;
 6185                            if point_range.contains(&buffer_row) {
 6186                                Some(code_actions)
 6187                            } else {
 6188                                None
 6189                            }
 6190                        })
 6191                })
 6192                .ok()
 6193                .flatten()
 6194        })
 6195    }
 6196
 6197    pub fn confirm_code_action(
 6198        &mut self,
 6199        action: &ConfirmCodeAction,
 6200        window: &mut Window,
 6201        cx: &mut Context<Self>,
 6202    ) -> Option<Task<Result<()>>> {
 6203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6204
 6205        let actions_menu =
 6206            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6207                menu
 6208            } else {
 6209                return None;
 6210            };
 6211
 6212        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6213        let action = actions_menu.actions.get(action_ix)?;
 6214        let title = action.label();
 6215        let buffer = actions_menu.buffer;
 6216        let workspace = self.workspace()?;
 6217
 6218        match action {
 6219            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6220                workspace.update(cx, |workspace, cx| {
 6221                    workspace.schedule_resolved_task(
 6222                        task_source_kind,
 6223                        resolved_task,
 6224                        false,
 6225                        window,
 6226                        cx,
 6227                    );
 6228
 6229                    Some(Task::ready(Ok(())))
 6230                })
 6231            }
 6232            CodeActionsItem::CodeAction {
 6233                excerpt_id,
 6234                action,
 6235                provider,
 6236            } => {
 6237                let apply_code_action =
 6238                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6239                let workspace = workspace.downgrade();
 6240                Some(cx.spawn_in(window, async move |editor, cx| {
 6241                    let project_transaction = apply_code_action.await?;
 6242                    Self::open_project_transaction(
 6243                        &editor,
 6244                        workspace,
 6245                        project_transaction,
 6246                        title,
 6247                        cx,
 6248                    )
 6249                    .await
 6250                }))
 6251            }
 6252            CodeActionsItem::DebugScenario(scenario) => {
 6253                let context = actions_menu.actions.context.clone();
 6254
 6255                workspace.update(cx, |workspace, cx| {
 6256                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6257                    workspace.start_debug_session(
 6258                        scenario,
 6259                        context,
 6260                        Some(buffer),
 6261                        None,
 6262                        window,
 6263                        cx,
 6264                    );
 6265                });
 6266                Some(Task::ready(Ok(())))
 6267            }
 6268        }
 6269    }
 6270
 6271    pub async fn open_project_transaction(
 6272        this: &WeakEntity<Editor>,
 6273        workspace: WeakEntity<Workspace>,
 6274        transaction: ProjectTransaction,
 6275        title: String,
 6276        cx: &mut AsyncWindowContext,
 6277    ) -> Result<()> {
 6278        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6279        cx.update(|_, cx| {
 6280            entries.sort_unstable_by_key(|(buffer, _)| {
 6281                buffer.read(cx).file().map(|f| f.path().clone())
 6282            });
 6283        })?;
 6284
 6285        // If the project transaction's edits are all contained within this editor, then
 6286        // avoid opening a new editor to display them.
 6287
 6288        if let Some((buffer, transaction)) = entries.first() {
 6289            if entries.len() == 1 {
 6290                let excerpt = this.update(cx, |editor, cx| {
 6291                    editor
 6292                        .buffer()
 6293                        .read(cx)
 6294                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6295                })?;
 6296                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6297                    if excerpted_buffer == *buffer {
 6298                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6299                            let excerpt_range = excerpt_range.to_offset(buffer);
 6300                            buffer
 6301                                .edited_ranges_for_transaction::<usize>(transaction)
 6302                                .all(|range| {
 6303                                    excerpt_range.start <= range.start
 6304                                        && excerpt_range.end >= range.end
 6305                                })
 6306                        })?;
 6307
 6308                        if all_edits_within_excerpt {
 6309                            return Ok(());
 6310                        }
 6311                    }
 6312                }
 6313            }
 6314        } else {
 6315            return Ok(());
 6316        }
 6317
 6318        let mut ranges_to_highlight = Vec::new();
 6319        let excerpt_buffer = cx.new(|cx| {
 6320            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6321            for (buffer_handle, transaction) in &entries {
 6322                let edited_ranges = buffer_handle
 6323                    .read(cx)
 6324                    .edited_ranges_for_transaction::<Point>(transaction)
 6325                    .collect::<Vec<_>>();
 6326                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6327                    PathKey::for_buffer(buffer_handle, cx),
 6328                    buffer_handle.clone(),
 6329                    edited_ranges,
 6330                    DEFAULT_MULTIBUFFER_CONTEXT,
 6331                    cx,
 6332                );
 6333
 6334                ranges_to_highlight.extend(ranges);
 6335            }
 6336            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6337            multibuffer
 6338        })?;
 6339
 6340        workspace.update_in(cx, |workspace, window, cx| {
 6341            let project = workspace.project().clone();
 6342            let editor =
 6343                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6344            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6345            editor.update(cx, |editor, cx| {
 6346                editor.highlight_background::<Self>(
 6347                    &ranges_to_highlight,
 6348                    |theme| theme.colors().editor_highlighted_line_background,
 6349                    cx,
 6350                );
 6351            });
 6352        })?;
 6353
 6354        Ok(())
 6355    }
 6356
 6357    pub fn clear_code_action_providers(&mut self) {
 6358        self.code_action_providers.clear();
 6359        self.available_code_actions.take();
 6360    }
 6361
 6362    pub fn add_code_action_provider(
 6363        &mut self,
 6364        provider: Rc<dyn CodeActionProvider>,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) {
 6368        if self
 6369            .code_action_providers
 6370            .iter()
 6371            .any(|existing_provider| existing_provider.id() == provider.id())
 6372        {
 6373            return;
 6374        }
 6375
 6376        self.code_action_providers.push(provider);
 6377        self.refresh_code_actions(window, cx);
 6378    }
 6379
 6380    pub fn remove_code_action_provider(
 6381        &mut self,
 6382        id: Arc<str>,
 6383        window: &mut Window,
 6384        cx: &mut Context<Self>,
 6385    ) {
 6386        self.code_action_providers
 6387            .retain(|provider| provider.id() != id);
 6388        self.refresh_code_actions(window, cx);
 6389    }
 6390
 6391    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6392        !self.code_action_providers.is_empty()
 6393            && EditorSettings::get_global(cx).toolbar.code_actions
 6394    }
 6395
 6396    pub fn has_available_code_actions(&self) -> bool {
 6397        self.available_code_actions
 6398            .as_ref()
 6399            .is_some_and(|(_, actions)| !actions.is_empty())
 6400    }
 6401
 6402    fn render_inline_code_actions(
 6403        &self,
 6404        icon_size: ui::IconSize,
 6405        display_row: DisplayRow,
 6406        is_active: bool,
 6407        cx: &mut Context<Self>,
 6408    ) -> AnyElement {
 6409        let show_tooltip = !self.context_menu_visible();
 6410        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6411            .icon_size(icon_size)
 6412            .shape(ui::IconButtonShape::Square)
 6413            .style(ButtonStyle::Transparent)
 6414            .icon_color(ui::Color::Hidden)
 6415            .toggle_state(is_active)
 6416            .when(show_tooltip, |this| {
 6417                this.tooltip({
 6418                    let focus_handle = self.focus_handle.clone();
 6419                    move |window, cx| {
 6420                        Tooltip::for_action_in(
 6421                            "Toggle Code Actions",
 6422                            &ToggleCodeActions {
 6423                                deployed_from: None,
 6424                                quick_launch: false,
 6425                            },
 6426                            &focus_handle,
 6427                            window,
 6428                            cx,
 6429                        )
 6430                    }
 6431                })
 6432            })
 6433            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6434                window.focus(&editor.focus_handle(cx));
 6435                editor.toggle_code_actions(
 6436                    &crate::actions::ToggleCodeActions {
 6437                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6438                            display_row,
 6439                        )),
 6440                        quick_launch: false,
 6441                    },
 6442                    window,
 6443                    cx,
 6444                );
 6445            }))
 6446            .into_any_element()
 6447    }
 6448
 6449    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6450        &self.context_menu
 6451    }
 6452
 6453    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6454        let newest_selection = self.selections.newest_anchor().clone();
 6455        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6456        let buffer = self.buffer.read(cx);
 6457        if newest_selection.head().diff_base_anchor.is_some() {
 6458            return None;
 6459        }
 6460        let (start_buffer, start) =
 6461            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6462        let (end_buffer, end) =
 6463            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6464        if start_buffer != end_buffer {
 6465            return None;
 6466        }
 6467
 6468        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6469            cx.background_executor()
 6470                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6471                .await;
 6472
 6473            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6474                let providers = this.code_action_providers.clone();
 6475                let tasks = this
 6476                    .code_action_providers
 6477                    .iter()
 6478                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6479                    .collect::<Vec<_>>();
 6480                (providers, tasks)
 6481            })?;
 6482
 6483            let mut actions = Vec::new();
 6484            for (provider, provider_actions) in
 6485                providers.into_iter().zip(future::join_all(tasks).await)
 6486            {
 6487                if let Some(provider_actions) = provider_actions.log_err() {
 6488                    actions.extend(provider_actions.into_iter().map(|action| {
 6489                        AvailableCodeAction {
 6490                            excerpt_id: newest_selection.start.excerpt_id,
 6491                            action,
 6492                            provider: provider.clone(),
 6493                        }
 6494                    }));
 6495                }
 6496            }
 6497
 6498            this.update(cx, |this, cx| {
 6499                this.available_code_actions = if actions.is_empty() {
 6500                    None
 6501                } else {
 6502                    Some((
 6503                        Location {
 6504                            buffer: start_buffer,
 6505                            range: start..end,
 6506                        },
 6507                        actions.into(),
 6508                    ))
 6509                };
 6510                cx.notify();
 6511            })
 6512        }));
 6513        None
 6514    }
 6515
 6516    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6517        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6518            self.show_git_blame_inline = false;
 6519
 6520            self.show_git_blame_inline_delay_task =
 6521                Some(cx.spawn_in(window, async move |this, cx| {
 6522                    cx.background_executor().timer(delay).await;
 6523
 6524                    this.update(cx, |this, cx| {
 6525                        this.show_git_blame_inline = true;
 6526                        cx.notify();
 6527                    })
 6528                    .log_err();
 6529                }));
 6530        }
 6531    }
 6532
 6533    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6534        let snapshot = self.snapshot(window, cx);
 6535        let cursor = self.selections.newest::<Point>(cx).head();
 6536        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6537        else {
 6538            return;
 6539        };
 6540
 6541        let Some(blame) = self.blame.as_ref() else {
 6542            return;
 6543        };
 6544
 6545        let row_info = RowInfo {
 6546            buffer_id: Some(buffer.remote_id()),
 6547            buffer_row: Some(point.row),
 6548            ..Default::default()
 6549        };
 6550        let Some(blame_entry) = blame
 6551            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6552            .flatten()
 6553        else {
 6554            return;
 6555        };
 6556
 6557        let anchor = self.selections.newest_anchor().head();
 6558        let position = self.to_pixel_point(anchor, &snapshot, window);
 6559        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6560            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6561        };
 6562    }
 6563
 6564    fn show_blame_popover(
 6565        &mut self,
 6566        blame_entry: &BlameEntry,
 6567        position: gpui::Point<Pixels>,
 6568        ignore_timeout: bool,
 6569        cx: &mut Context<Self>,
 6570    ) {
 6571        if let Some(state) = &mut self.inline_blame_popover {
 6572            state.hide_task.take();
 6573        } else {
 6574            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6575            let blame_entry = blame_entry.clone();
 6576            let show_task = cx.spawn(async move |editor, cx| {
 6577                if !ignore_timeout {
 6578                    cx.background_executor()
 6579                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6580                        .await;
 6581                }
 6582                editor
 6583                    .update(cx, |editor, cx| {
 6584                        editor.inline_blame_popover_show_task.take();
 6585                        let Some(blame) = editor.blame.as_ref() else {
 6586                            return;
 6587                        };
 6588                        let blame = blame.read(cx);
 6589                        let details = blame.details_for_entry(&blame_entry);
 6590                        let markdown = cx.new(|cx| {
 6591                            Markdown::new(
 6592                                details
 6593                                    .as_ref()
 6594                                    .map(|message| message.message.clone())
 6595                                    .unwrap_or_default(),
 6596                                None,
 6597                                None,
 6598                                cx,
 6599                            )
 6600                        });
 6601                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6602                            position,
 6603                            hide_task: None,
 6604                            popover_bounds: None,
 6605                            popover_state: InlineBlamePopoverState {
 6606                                scroll_handle: ScrollHandle::new(),
 6607                                commit_message: details,
 6608                                markdown,
 6609                            },
 6610                            keyboard_grace: ignore_timeout,
 6611                        });
 6612                        cx.notify();
 6613                    })
 6614                    .ok();
 6615            });
 6616            self.inline_blame_popover_show_task = Some(show_task);
 6617        }
 6618    }
 6619
 6620    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6621        self.inline_blame_popover_show_task.take();
 6622        if let Some(state) = &mut self.inline_blame_popover {
 6623            let hide_task = cx.spawn(async move |editor, cx| {
 6624                cx.background_executor()
 6625                    .timer(std::time::Duration::from_millis(100))
 6626                    .await;
 6627                editor
 6628                    .update(cx, |editor, cx| {
 6629                        editor.inline_blame_popover.take();
 6630                        cx.notify();
 6631                    })
 6632                    .ok();
 6633            });
 6634            state.hide_task = Some(hide_task);
 6635        }
 6636    }
 6637
 6638    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6639        if self.pending_rename.is_some() {
 6640            return None;
 6641        }
 6642
 6643        let provider = self.semantics_provider.clone()?;
 6644        let buffer = self.buffer.read(cx);
 6645        let newest_selection = self.selections.newest_anchor().clone();
 6646        let cursor_position = newest_selection.head();
 6647        let (cursor_buffer, cursor_buffer_position) =
 6648            buffer.text_anchor_for_position(cursor_position, cx)?;
 6649        let (tail_buffer, tail_buffer_position) =
 6650            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6651        if cursor_buffer != tail_buffer {
 6652            return None;
 6653        }
 6654
 6655        let snapshot = cursor_buffer.read(cx).snapshot();
 6656        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6657        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6658        if start_word_range != end_word_range {
 6659            self.document_highlights_task.take();
 6660            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6661            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6662            return None;
 6663        }
 6664
 6665        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6666        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6667            cx.background_executor()
 6668                .timer(Duration::from_millis(debounce))
 6669                .await;
 6670
 6671            let highlights = if let Some(highlights) = cx
 6672                .update(|cx| {
 6673                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6674                })
 6675                .ok()
 6676                .flatten()
 6677            {
 6678                highlights.await.log_err()
 6679            } else {
 6680                None
 6681            };
 6682
 6683            if let Some(highlights) = highlights {
 6684                this.update(cx, |this, cx| {
 6685                    if this.pending_rename.is_some() {
 6686                        return;
 6687                    }
 6688
 6689                    let buffer_id = cursor_position.buffer_id;
 6690                    let buffer = this.buffer.read(cx);
 6691                    if !buffer
 6692                        .text_anchor_for_position(cursor_position, cx)
 6693                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6694                    {
 6695                        return;
 6696                    }
 6697
 6698                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6699                    let mut write_ranges = Vec::new();
 6700                    let mut read_ranges = Vec::new();
 6701                    for highlight in highlights {
 6702                        for (excerpt_id, excerpt_range) in
 6703                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6704                        {
 6705                            let start = highlight
 6706                                .range
 6707                                .start
 6708                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6709                            let end = highlight
 6710                                .range
 6711                                .end
 6712                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6713                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6714                                continue;
 6715                            }
 6716
 6717                            let range = Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: start,
 6721                                diff_base_anchor: None,
 6722                            }..Anchor {
 6723                                buffer_id,
 6724                                excerpt_id,
 6725                                text_anchor: end,
 6726                                diff_base_anchor: None,
 6727                            };
 6728                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6729                                write_ranges.push(range);
 6730                            } else {
 6731                                read_ranges.push(range);
 6732                            }
 6733                        }
 6734                    }
 6735
 6736                    this.highlight_background::<DocumentHighlightRead>(
 6737                        &read_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_read_background,
 6739                        cx,
 6740                    );
 6741                    this.highlight_background::<DocumentHighlightWrite>(
 6742                        &write_ranges,
 6743                        |theme| theme.colors().editor_document_highlight_write_background,
 6744                        cx,
 6745                    );
 6746                    cx.notify();
 6747                })
 6748                .log_err();
 6749            }
 6750        }));
 6751        None
 6752    }
 6753
 6754    fn prepare_highlight_query_from_selection(
 6755        &mut self,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Option<(String, Range<Anchor>)> {
 6758        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6759            return None;
 6760        }
 6761        if !EditorSettings::get_global(cx).selection_highlight {
 6762            return None;
 6763        }
 6764        if self.selections.count() != 1 || self.selections.line_mode {
 6765            return None;
 6766        }
 6767        let selection = self.selections.newest::<Point>(cx);
 6768        if selection.is_empty() || selection.start.row != selection.end.row {
 6769            return None;
 6770        }
 6771        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6772        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6773        let query = multi_buffer_snapshot
 6774            .text_for_range(selection_anchor_range.clone())
 6775            .collect::<String>();
 6776        if query.trim().is_empty() {
 6777            return None;
 6778        }
 6779        Some((query, selection_anchor_range))
 6780    }
 6781
 6782    fn update_selection_occurrence_highlights(
 6783        &mut self,
 6784        query_text: String,
 6785        query_range: Range<Anchor>,
 6786        multi_buffer_range_to_query: Range<Point>,
 6787        use_debounce: bool,
 6788        window: &mut Window,
 6789        cx: &mut Context<Editor>,
 6790    ) -> Task<()> {
 6791        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6792        cx.spawn_in(window, async move |editor, cx| {
 6793            if use_debounce {
 6794                cx.background_executor()
 6795                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6796                    .await;
 6797            }
 6798            let match_task = cx.background_spawn(async move {
 6799                let buffer_ranges = multi_buffer_snapshot
 6800                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6801                    .into_iter()
 6802                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6803                let mut match_ranges = Vec::new();
 6804                let Ok(regex) = project::search::SearchQuery::text(
 6805                    query_text.clone(),
 6806                    false,
 6807                    false,
 6808                    false,
 6809                    Default::default(),
 6810                    Default::default(),
 6811                    false,
 6812                    None,
 6813                ) else {
 6814                    return Vec::default();
 6815                };
 6816                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6817                    match_ranges.extend(
 6818                        regex
 6819                            .search(&buffer_snapshot, Some(search_range.clone()))
 6820                            .await
 6821                            .into_iter()
 6822                            .filter_map(|match_range| {
 6823                                let match_start = buffer_snapshot
 6824                                    .anchor_after(search_range.start + match_range.start);
 6825                                let match_end = buffer_snapshot
 6826                                    .anchor_before(search_range.start + match_range.end);
 6827                                let match_anchor_range = Anchor::range_in_buffer(
 6828                                    excerpt_id,
 6829                                    buffer_snapshot.remote_id(),
 6830                                    match_start..match_end,
 6831                                );
 6832                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6833                            }),
 6834                    );
 6835                }
 6836                match_ranges
 6837            });
 6838            let match_ranges = match_task.await;
 6839            editor
 6840                .update_in(cx, |editor, _, cx| {
 6841                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6842                    if !match_ranges.is_empty() {
 6843                        editor.highlight_background::<SelectedTextHighlight>(
 6844                            &match_ranges,
 6845                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6846                            cx,
 6847                        )
 6848                    }
 6849                })
 6850                .log_err();
 6851        })
 6852    }
 6853
 6854    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6855        struct NewlineFold;
 6856        let type_id = std::any::TypeId::of::<NewlineFold>();
 6857        if !self.mode.is_single_line() {
 6858            return;
 6859        }
 6860        let snapshot = self.snapshot(window, cx);
 6861        if snapshot.buffer_snapshot.max_point().row == 0 {
 6862            return;
 6863        }
 6864        let task = cx.background_spawn(async move {
 6865            let new_newlines = snapshot
 6866                .buffer_chars_at(0)
 6867                .filter_map(|(c, i)| {
 6868                    if c == '\n' {
 6869                        Some(
 6870                            snapshot.buffer_snapshot.anchor_after(i)
 6871                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6872                        )
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878            let existing_newlines = snapshot
 6879                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6880                .filter_map(|fold| {
 6881                    if fold.placeholder.type_tag == Some(type_id) {
 6882                        Some(fold.range.start..fold.range.end)
 6883                    } else {
 6884                        None
 6885                    }
 6886                })
 6887                .collect::<Vec<_>>();
 6888
 6889            (new_newlines, existing_newlines)
 6890        });
 6891        self.folding_newlines = cx.spawn(async move |this, cx| {
 6892            let (new_newlines, existing_newlines) = task.await;
 6893            if new_newlines == existing_newlines {
 6894                return;
 6895            }
 6896            let placeholder = FoldPlaceholder {
 6897                render: Arc::new(move |_, _, cx| {
 6898                    div()
 6899                        .bg(cx.theme().status().hint_background)
 6900                        .border_b_1()
 6901                        .size_full()
 6902                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6903                        .border_color(cx.theme().status().hint)
 6904                        .child("\\n")
 6905                        .into_any()
 6906                }),
 6907                constrain_width: false,
 6908                merge_adjacent: false,
 6909                type_tag: Some(type_id),
 6910            };
 6911            let creases = new_newlines
 6912                .into_iter()
 6913                .map(|range| Crease::simple(range, placeholder.clone()))
 6914                .collect();
 6915            this.update(cx, |this, cx| {
 6916                this.display_map.update(cx, |display_map, cx| {
 6917                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6918                    display_map.fold(creases, cx);
 6919                });
 6920            })
 6921            .ok();
 6922        });
 6923    }
 6924
 6925    fn refresh_selected_text_highlights(
 6926        &mut self,
 6927        on_buffer_edit: bool,
 6928        window: &mut Window,
 6929        cx: &mut Context<Editor>,
 6930    ) {
 6931        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6932        else {
 6933            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6934            self.quick_selection_highlight_task.take();
 6935            self.debounced_selection_highlight_task.take();
 6936            return;
 6937        };
 6938        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6939        if on_buffer_edit
 6940            || self
 6941                .quick_selection_highlight_task
 6942                .as_ref()
 6943                .map_or(true, |(prev_anchor_range, _)| {
 6944                    prev_anchor_range != &query_range
 6945                })
 6946        {
 6947            let multi_buffer_visible_start = self
 6948                .scroll_manager
 6949                .anchor()
 6950                .anchor
 6951                .to_point(&multi_buffer_snapshot);
 6952            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6953                multi_buffer_visible_start
 6954                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6955                Bias::Left,
 6956            );
 6957            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6958            self.quick_selection_highlight_task = Some((
 6959                query_range.clone(),
 6960                self.update_selection_occurrence_highlights(
 6961                    query_text.clone(),
 6962                    query_range.clone(),
 6963                    multi_buffer_visible_range,
 6964                    false,
 6965                    window,
 6966                    cx,
 6967                ),
 6968            ));
 6969        }
 6970        if on_buffer_edit
 6971            || self
 6972                .debounced_selection_highlight_task
 6973                .as_ref()
 6974                .map_or(true, |(prev_anchor_range, _)| {
 6975                    prev_anchor_range != &query_range
 6976                })
 6977        {
 6978            let multi_buffer_start = multi_buffer_snapshot
 6979                .anchor_before(0)
 6980                .to_point(&multi_buffer_snapshot);
 6981            let multi_buffer_end = multi_buffer_snapshot
 6982                .anchor_after(multi_buffer_snapshot.len())
 6983                .to_point(&multi_buffer_snapshot);
 6984            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6985            self.debounced_selection_highlight_task = Some((
 6986                query_range.clone(),
 6987                self.update_selection_occurrence_highlights(
 6988                    query_text,
 6989                    query_range,
 6990                    multi_buffer_full_range,
 6991                    true,
 6992                    window,
 6993                    cx,
 6994                ),
 6995            ));
 6996        }
 6997    }
 6998
 6999    pub fn refresh_inline_completion(
 7000        &mut self,
 7001        debounce: bool,
 7002        user_requested: bool,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) -> Option<()> {
 7006        if DisableAiSettings::get_global(cx).disable_ai {
 7007            return None;
 7008        }
 7009
 7010        let provider = self.edit_prediction_provider()?;
 7011        let cursor = self.selections.newest_anchor().head();
 7012        let (buffer, cursor_buffer_position) =
 7013            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7014
 7015        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7016            self.discard_inline_completion(false, cx);
 7017            return None;
 7018        }
 7019
 7020        if !user_requested
 7021            && (!self.should_show_edit_predictions()
 7022                || !self.is_focused(window)
 7023                || buffer.read(cx).is_empty())
 7024        {
 7025            self.discard_inline_completion(false, cx);
 7026            return None;
 7027        }
 7028
 7029        self.update_visible_inline_completion(window, cx);
 7030        provider.refresh(
 7031            self.project.clone(),
 7032            buffer,
 7033            cursor_buffer_position,
 7034            debounce,
 7035            cx,
 7036        );
 7037        Some(())
 7038    }
 7039
 7040    fn show_edit_predictions_in_menu(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7044        }
 7045    }
 7046
 7047    pub fn edit_predictions_enabled(&self) -> bool {
 7048        match self.edit_prediction_settings {
 7049            EditPredictionSettings::Disabled => false,
 7050            EditPredictionSettings::Enabled { .. } => true,
 7051        }
 7052    }
 7053
 7054    fn edit_prediction_requires_modifier(&self) -> bool {
 7055        match self.edit_prediction_settings {
 7056            EditPredictionSettings::Disabled => false,
 7057            EditPredictionSettings::Enabled {
 7058                preview_requires_modifier,
 7059                ..
 7060            } => preview_requires_modifier,
 7061        }
 7062    }
 7063
 7064    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7065        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7066            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7067            self.discard_inline_completion(false, cx);
 7068        } else {
 7069            let selection = self.selections.newest_anchor();
 7070            let cursor = selection.head();
 7071
 7072            if let Some((buffer, cursor_buffer_position)) =
 7073                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7074            {
 7075                self.edit_prediction_settings =
 7076                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7077            }
 7078        }
 7079    }
 7080
 7081    fn edit_prediction_settings_at_position(
 7082        &self,
 7083        buffer: &Entity<Buffer>,
 7084        buffer_position: language::Anchor,
 7085        cx: &App,
 7086    ) -> EditPredictionSettings {
 7087        if !self.mode.is_full()
 7088            || !self.show_inline_completions_override.unwrap_or(true)
 7089            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7090        {
 7091            return EditPredictionSettings::Disabled;
 7092        }
 7093
 7094        let buffer = buffer.read(cx);
 7095
 7096        let file = buffer.file();
 7097
 7098        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7099            return EditPredictionSettings::Disabled;
 7100        };
 7101
 7102        let by_provider = matches!(
 7103            self.menu_inline_completions_policy,
 7104            MenuInlineCompletionsPolicy::ByProvider
 7105        );
 7106
 7107        let show_in_menu = by_provider
 7108            && self
 7109                .edit_prediction_provider
 7110                .as_ref()
 7111                .map_or(false, |provider| {
 7112                    provider.provider.show_completions_in_menu()
 7113                });
 7114
 7115        let preview_requires_modifier =
 7116            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7117
 7118        EditPredictionSettings::Enabled {
 7119            show_in_menu,
 7120            preview_requires_modifier,
 7121        }
 7122    }
 7123
 7124    fn should_show_edit_predictions(&self) -> bool {
 7125        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7126    }
 7127
 7128    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7129        matches!(
 7130            self.edit_prediction_preview,
 7131            EditPredictionPreview::Active { .. }
 7132        )
 7133    }
 7134
 7135    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7136        let cursor = self.selections.newest_anchor().head();
 7137        if let Some((buffer, cursor_position)) =
 7138            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7139        {
 7140            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7141        } else {
 7142            false
 7143        }
 7144    }
 7145
 7146    pub fn supports_minimap(&self, cx: &App) -> bool {
 7147        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7148    }
 7149
 7150    fn edit_predictions_enabled_in_buffer(
 7151        &self,
 7152        buffer: &Entity<Buffer>,
 7153        buffer_position: language::Anchor,
 7154        cx: &App,
 7155    ) -> bool {
 7156        maybe!({
 7157            if self.read_only(cx) {
 7158                return Some(false);
 7159            }
 7160            let provider = self.edit_prediction_provider()?;
 7161            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7162                return Some(false);
 7163            }
 7164            let buffer = buffer.read(cx);
 7165            let Some(file) = buffer.file() else {
 7166                return Some(true);
 7167            };
 7168            let settings = all_language_settings(Some(file), cx);
 7169            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7170        })
 7171        .unwrap_or(false)
 7172    }
 7173
 7174    fn cycle_inline_completion(
 7175        &mut self,
 7176        direction: Direction,
 7177        window: &mut Window,
 7178        cx: &mut Context<Self>,
 7179    ) -> Option<()> {
 7180        let provider = self.edit_prediction_provider()?;
 7181        let cursor = self.selections.newest_anchor().head();
 7182        let (buffer, cursor_buffer_position) =
 7183            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7184        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7185            return None;
 7186        }
 7187
 7188        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7189        self.update_visible_inline_completion(window, cx);
 7190
 7191        Some(())
 7192    }
 7193
 7194    pub fn show_inline_completion(
 7195        &mut self,
 7196        _: &ShowEditPrediction,
 7197        window: &mut Window,
 7198        cx: &mut Context<Self>,
 7199    ) {
 7200        if !self.has_active_inline_completion() {
 7201            self.refresh_inline_completion(false, true, window, cx);
 7202            return;
 7203        }
 7204
 7205        self.update_visible_inline_completion(window, cx);
 7206    }
 7207
 7208    pub fn display_cursor_names(
 7209        &mut self,
 7210        _: &DisplayCursorNames,
 7211        window: &mut Window,
 7212        cx: &mut Context<Self>,
 7213    ) {
 7214        self.show_cursor_names(window, cx);
 7215    }
 7216
 7217    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7218        self.show_cursor_names = true;
 7219        cx.notify();
 7220        cx.spawn_in(window, async move |this, cx| {
 7221            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7222            this.update(cx, |this, cx| {
 7223                this.show_cursor_names = false;
 7224                cx.notify()
 7225            })
 7226            .ok()
 7227        })
 7228        .detach();
 7229    }
 7230
 7231    pub fn next_edit_prediction(
 7232        &mut self,
 7233        _: &NextEditPrediction,
 7234        window: &mut Window,
 7235        cx: &mut Context<Self>,
 7236    ) {
 7237        if self.has_active_inline_completion() {
 7238            self.cycle_inline_completion(Direction::Next, window, cx);
 7239        } else {
 7240            let is_copilot_disabled = self
 7241                .refresh_inline_completion(false, true, window, cx)
 7242                .is_none();
 7243            if is_copilot_disabled {
 7244                cx.propagate();
 7245            }
 7246        }
 7247    }
 7248
 7249    pub fn previous_edit_prediction(
 7250        &mut self,
 7251        _: &PreviousEditPrediction,
 7252        window: &mut Window,
 7253        cx: &mut Context<Self>,
 7254    ) {
 7255        if self.has_active_inline_completion() {
 7256            self.cycle_inline_completion(Direction::Prev, window, cx);
 7257        } else {
 7258            let is_copilot_disabled = self
 7259                .refresh_inline_completion(false, true, window, cx)
 7260                .is_none();
 7261            if is_copilot_disabled {
 7262                cx.propagate();
 7263            }
 7264        }
 7265    }
 7266
 7267    pub fn accept_edit_prediction(
 7268        &mut self,
 7269        _: &AcceptEditPrediction,
 7270        window: &mut Window,
 7271        cx: &mut Context<Self>,
 7272    ) {
 7273        if self.show_edit_predictions_in_menu() {
 7274            self.hide_context_menu(window, cx);
 7275        }
 7276
 7277        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7278            return;
 7279        };
 7280
 7281        self.report_inline_completion_event(
 7282            active_inline_completion.completion_id.clone(),
 7283            true,
 7284            cx,
 7285        );
 7286
 7287        match &active_inline_completion.completion {
 7288            InlineCompletion::Move { target, .. } => {
 7289                let target = *target;
 7290
 7291                if let Some(position_map) = &self.last_position_map {
 7292                    if position_map
 7293                        .visible_row_range
 7294                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7295                        || !self.edit_prediction_requires_modifier()
 7296                    {
 7297                        self.unfold_ranges(&[target..target], true, false, cx);
 7298                        // Note that this is also done in vim's handler of the Tab action.
 7299                        self.change_selections(
 7300                            SelectionEffects::scroll(Autoscroll::newest()),
 7301                            window,
 7302                            cx,
 7303                            |selections| {
 7304                                selections.select_anchor_ranges([target..target]);
 7305                            },
 7306                        );
 7307                        self.clear_row_highlights::<EditPredictionPreview>();
 7308
 7309                        self.edit_prediction_preview
 7310                            .set_previous_scroll_position(None);
 7311                    } else {
 7312                        self.edit_prediction_preview
 7313                            .set_previous_scroll_position(Some(
 7314                                position_map.snapshot.scroll_anchor,
 7315                            ));
 7316
 7317                        self.highlight_rows::<EditPredictionPreview>(
 7318                            target..target,
 7319                            cx.theme().colors().editor_highlighted_line_background,
 7320                            RowHighlightOptions {
 7321                                autoscroll: true,
 7322                                ..Default::default()
 7323                            },
 7324                            cx,
 7325                        );
 7326                        self.request_autoscroll(Autoscroll::fit(), cx);
 7327                    }
 7328                }
 7329            }
 7330            InlineCompletion::Edit { edits, .. } => {
 7331                if let Some(provider) = self.edit_prediction_provider() {
 7332                    provider.accept(cx);
 7333                }
 7334
 7335                // Store the transaction ID and selections before applying the edit
 7336                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7337
 7338                let snapshot = self.buffer.read(cx).snapshot(cx);
 7339                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7340
 7341                self.buffer.update(cx, |buffer, cx| {
 7342                    buffer.edit(edits.iter().cloned(), None, cx)
 7343                });
 7344
 7345                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7346                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7347                });
 7348
 7349                let selections = self.selections.disjoint_anchors();
 7350                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7351                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7352                    if has_new_transaction {
 7353                        self.selection_history
 7354                            .insert_transaction(transaction_id_now, selections);
 7355                    }
 7356                }
 7357
 7358                self.update_visible_inline_completion(window, cx);
 7359                if self.active_inline_completion.is_none() {
 7360                    self.refresh_inline_completion(true, true, window, cx);
 7361                }
 7362
 7363                cx.notify();
 7364            }
 7365        }
 7366
 7367        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7368    }
 7369
 7370    pub fn accept_partial_inline_completion(
 7371        &mut self,
 7372        _: &AcceptPartialEditPrediction,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) {
 7376        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7377            return;
 7378        };
 7379        if self.selections.count() != 1 {
 7380            return;
 7381        }
 7382
 7383        self.report_inline_completion_event(
 7384            active_inline_completion.completion_id.clone(),
 7385            true,
 7386            cx,
 7387        );
 7388
 7389        match &active_inline_completion.completion {
 7390            InlineCompletion::Move { target, .. } => {
 7391                let target = *target;
 7392                self.change_selections(
 7393                    SelectionEffects::scroll(Autoscroll::newest()),
 7394                    window,
 7395                    cx,
 7396                    |selections| {
 7397                        selections.select_anchor_ranges([target..target]);
 7398                    },
 7399                );
 7400            }
 7401            InlineCompletion::Edit { edits, .. } => {
 7402                // Find an insertion that starts at the cursor position.
 7403                let snapshot = self.buffer.read(cx).snapshot(cx);
 7404                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7405                let insertion = edits.iter().find_map(|(range, text)| {
 7406                    let range = range.to_offset(&snapshot);
 7407                    if range.is_empty() && range.start == cursor_offset {
 7408                        Some(text)
 7409                    } else {
 7410                        None
 7411                    }
 7412                });
 7413
 7414                if let Some(text) = insertion {
 7415                    let mut partial_completion = text
 7416                        .chars()
 7417                        .by_ref()
 7418                        .take_while(|c| c.is_alphabetic())
 7419                        .collect::<String>();
 7420                    if partial_completion.is_empty() {
 7421                        partial_completion = text
 7422                            .chars()
 7423                            .by_ref()
 7424                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7425                            .collect::<String>();
 7426                    }
 7427
 7428                    cx.emit(EditorEvent::InputHandled {
 7429                        utf16_range_to_replace: None,
 7430                        text: partial_completion.clone().into(),
 7431                    });
 7432
 7433                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7434
 7435                    self.refresh_inline_completion(true, true, window, cx);
 7436                    cx.notify();
 7437                } else {
 7438                    self.accept_edit_prediction(&Default::default(), window, cx);
 7439                }
 7440            }
 7441        }
 7442    }
 7443
 7444    fn discard_inline_completion(
 7445        &mut self,
 7446        should_report_inline_completion_event: bool,
 7447        cx: &mut Context<Self>,
 7448    ) -> bool {
 7449        if should_report_inline_completion_event {
 7450            let completion_id = self
 7451                .active_inline_completion
 7452                .as_ref()
 7453                .and_then(|active_completion| active_completion.completion_id.clone());
 7454
 7455            self.report_inline_completion_event(completion_id, false, cx);
 7456        }
 7457
 7458        if let Some(provider) = self.edit_prediction_provider() {
 7459            provider.discard(cx);
 7460        }
 7461
 7462        self.take_active_inline_completion(cx)
 7463    }
 7464
 7465    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7466        let Some(provider) = self.edit_prediction_provider() else {
 7467            return;
 7468        };
 7469
 7470        let Some((_, buffer, _)) = self
 7471            .buffer
 7472            .read(cx)
 7473            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7474        else {
 7475            return;
 7476        };
 7477
 7478        let extension = buffer
 7479            .read(cx)
 7480            .file()
 7481            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7482
 7483        let event_type = match accepted {
 7484            true => "Edit Prediction Accepted",
 7485            false => "Edit Prediction Discarded",
 7486        };
 7487        telemetry::event!(
 7488            event_type,
 7489            provider = provider.name(),
 7490            prediction_id = id,
 7491            suggestion_accepted = accepted,
 7492            file_extension = extension,
 7493        );
 7494    }
 7495
 7496    pub fn has_active_inline_completion(&self) -> bool {
 7497        self.active_inline_completion.is_some()
 7498    }
 7499
 7500    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7501        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7502            return false;
 7503        };
 7504
 7505        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7506        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7507        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7508        true
 7509    }
 7510
 7511    /// Returns true when we're displaying the edit prediction popover below the cursor
 7512    /// like we are not previewing and the LSP autocomplete menu is visible
 7513    /// or we are in `when_holding_modifier` mode.
 7514    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7515        if self.edit_prediction_preview_is_active()
 7516            || !self.show_edit_predictions_in_menu()
 7517            || !self.edit_predictions_enabled()
 7518        {
 7519            return false;
 7520        }
 7521
 7522        if self.has_visible_completions_menu() {
 7523            return true;
 7524        }
 7525
 7526        has_completion && self.edit_prediction_requires_modifier()
 7527    }
 7528
 7529    fn handle_modifiers_changed(
 7530        &mut self,
 7531        modifiers: Modifiers,
 7532        position_map: &PositionMap,
 7533        window: &mut Window,
 7534        cx: &mut Context<Self>,
 7535    ) {
 7536        if self.show_edit_predictions_in_menu() {
 7537            self.update_edit_prediction_preview(&modifiers, window, cx);
 7538        }
 7539
 7540        self.update_selection_mode(&modifiers, position_map, window, cx);
 7541
 7542        let mouse_position = window.mouse_position();
 7543        if !position_map.text_hitbox.is_hovered(window) {
 7544            return;
 7545        }
 7546
 7547        self.update_hovered_link(
 7548            position_map.point_for_position(mouse_position),
 7549            &position_map.snapshot,
 7550            modifiers,
 7551            window,
 7552            cx,
 7553        )
 7554    }
 7555
 7556    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7557        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7558        if invert {
 7559            match multi_cursor_setting {
 7560                MultiCursorModifier::Alt => modifiers.alt,
 7561                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7562            }
 7563        } else {
 7564            match multi_cursor_setting {
 7565                MultiCursorModifier::Alt => modifiers.secondary(),
 7566                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7567            }
 7568        }
 7569    }
 7570
 7571    fn columnar_selection_mode(
 7572        modifiers: &Modifiers,
 7573        cx: &mut Context<Self>,
 7574    ) -> Option<ColumnarMode> {
 7575        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7576            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7577                Some(ColumnarMode::FromMouse)
 7578            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7579                Some(ColumnarMode::FromSelection)
 7580            } else {
 7581                None
 7582            }
 7583        } else {
 7584            None
 7585        }
 7586    }
 7587
 7588    fn update_selection_mode(
 7589        &mut self,
 7590        modifiers: &Modifiers,
 7591        position_map: &PositionMap,
 7592        window: &mut Window,
 7593        cx: &mut Context<Self>,
 7594    ) {
 7595        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7596            return;
 7597        };
 7598        if self.selections.pending.is_none() {
 7599            return;
 7600        }
 7601
 7602        let mouse_position = window.mouse_position();
 7603        let point_for_position = position_map.point_for_position(mouse_position);
 7604        let position = point_for_position.previous_valid;
 7605
 7606        self.select(
 7607            SelectPhase::BeginColumnar {
 7608                position,
 7609                reset: false,
 7610                mode,
 7611                goal_column: point_for_position.exact_unclipped.column(),
 7612            },
 7613            window,
 7614            cx,
 7615        );
 7616    }
 7617
 7618    fn update_edit_prediction_preview(
 7619        &mut self,
 7620        modifiers: &Modifiers,
 7621        window: &mut Window,
 7622        cx: &mut Context<Self>,
 7623    ) {
 7624        let mut modifiers_held = false;
 7625        if let Some(accept_keystroke) = self
 7626            .accept_edit_prediction_keybind(false, window, cx)
 7627            .keystroke()
 7628        {
 7629            modifiers_held = modifiers_held
 7630                || (&accept_keystroke.modifiers == modifiers
 7631                    && accept_keystroke.modifiers.modified());
 7632        };
 7633        if let Some(accept_partial_keystroke) = self
 7634            .accept_edit_prediction_keybind(true, window, cx)
 7635            .keystroke()
 7636        {
 7637            modifiers_held = modifiers_held
 7638                || (&accept_partial_keystroke.modifiers == modifiers
 7639                    && accept_partial_keystroke.modifiers.modified());
 7640        }
 7641
 7642        if modifiers_held {
 7643            if matches!(
 7644                self.edit_prediction_preview,
 7645                EditPredictionPreview::Inactive { .. }
 7646            ) {
 7647                self.edit_prediction_preview = EditPredictionPreview::Active {
 7648                    previous_scroll_position: None,
 7649                    since: Instant::now(),
 7650                };
 7651
 7652                self.update_visible_inline_completion(window, cx);
 7653                cx.notify();
 7654            }
 7655        } else if let EditPredictionPreview::Active {
 7656            previous_scroll_position,
 7657            since,
 7658        } = self.edit_prediction_preview
 7659        {
 7660            if let (Some(previous_scroll_position), Some(position_map)) =
 7661                (previous_scroll_position, self.last_position_map.as_ref())
 7662            {
 7663                self.set_scroll_position(
 7664                    previous_scroll_position
 7665                        .scroll_position(&position_map.snapshot.display_snapshot),
 7666                    window,
 7667                    cx,
 7668                );
 7669            }
 7670
 7671            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7672                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7673            };
 7674            self.clear_row_highlights::<EditPredictionPreview>();
 7675            self.update_visible_inline_completion(window, cx);
 7676            cx.notify();
 7677        }
 7678    }
 7679
 7680    fn update_visible_inline_completion(
 7681        &mut self,
 7682        _window: &mut Window,
 7683        cx: &mut Context<Self>,
 7684    ) -> Option<()> {
 7685        if DisableAiSettings::get_global(cx).disable_ai {
 7686            return None;
 7687        }
 7688
 7689        let selection = self.selections.newest_anchor();
 7690        let cursor = selection.head();
 7691        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7692        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7693        let excerpt_id = cursor.excerpt_id;
 7694
 7695        let show_in_menu = self.show_edit_predictions_in_menu();
 7696        let completions_menu_has_precedence = !show_in_menu
 7697            && (self.context_menu.borrow().is_some()
 7698                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7699
 7700        if completions_menu_has_precedence
 7701            || !offset_selection.is_empty()
 7702            || self
 7703                .active_inline_completion
 7704                .as_ref()
 7705                .map_or(false, |completion| {
 7706                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7707                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7708                    !invalidation_range.contains(&offset_selection.head())
 7709                })
 7710        {
 7711            self.discard_inline_completion(false, cx);
 7712            return None;
 7713        }
 7714
 7715        self.take_active_inline_completion(cx);
 7716        let Some(provider) = self.edit_prediction_provider() else {
 7717            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7718            return None;
 7719        };
 7720
 7721        let (buffer, cursor_buffer_position) =
 7722            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7723
 7724        self.edit_prediction_settings =
 7725            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7726
 7727        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7728
 7729        if self.edit_prediction_indent_conflict {
 7730            let cursor_point = cursor.to_point(&multibuffer);
 7731
 7732            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7733
 7734            if let Some((_, indent)) = indents.iter().next() {
 7735                if indent.len == cursor_point.column {
 7736                    self.edit_prediction_indent_conflict = false;
 7737                }
 7738            }
 7739        }
 7740
 7741        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7742        let edits = inline_completion
 7743            .edits
 7744            .into_iter()
 7745            .flat_map(|(range, new_text)| {
 7746                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7747                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7748                Some((start..end, new_text))
 7749            })
 7750            .collect::<Vec<_>>();
 7751        if edits.is_empty() {
 7752            return None;
 7753        }
 7754
 7755        let first_edit_start = edits.first().unwrap().0.start;
 7756        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7757        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7758
 7759        let last_edit_end = edits.last().unwrap().0.end;
 7760        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7761        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7762
 7763        let cursor_row = cursor.to_point(&multibuffer).row;
 7764
 7765        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7766
 7767        let mut inlay_ids = Vec::new();
 7768        let invalidation_row_range;
 7769        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7770            Some(cursor_row..edit_end_row)
 7771        } else if cursor_row > edit_end_row {
 7772            Some(edit_start_row..cursor_row)
 7773        } else {
 7774            None
 7775        };
 7776        let is_move =
 7777            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7778        let completion = if is_move {
 7779            invalidation_row_range =
 7780                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7781            let target = first_edit_start;
 7782            InlineCompletion::Move { target, snapshot }
 7783        } else {
 7784            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7785                && !self.inline_completions_hidden_for_vim_mode;
 7786
 7787            if show_completions_in_buffer {
 7788                if edits
 7789                    .iter()
 7790                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7791                {
 7792                    let mut inlays = Vec::new();
 7793                    for (range, new_text) in &edits {
 7794                        let inlay = Inlay::inline_completion(
 7795                            post_inc(&mut self.next_inlay_id),
 7796                            range.start,
 7797                            new_text.as_str(),
 7798                        );
 7799                        inlay_ids.push(inlay.id);
 7800                        inlays.push(inlay);
 7801                    }
 7802
 7803                    self.splice_inlays(&[], inlays, cx);
 7804                } else {
 7805                    let background_color = cx.theme().status().deleted_background;
 7806                    self.highlight_text::<InlineCompletionHighlight>(
 7807                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7808                        HighlightStyle {
 7809                            background_color: Some(background_color),
 7810                            ..Default::default()
 7811                        },
 7812                        cx,
 7813                    );
 7814                }
 7815            }
 7816
 7817            invalidation_row_range = edit_start_row..edit_end_row;
 7818
 7819            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7820                if provider.show_tab_accept_marker() {
 7821                    EditDisplayMode::TabAccept
 7822                } else {
 7823                    EditDisplayMode::Inline
 7824                }
 7825            } else {
 7826                EditDisplayMode::DiffPopover
 7827            };
 7828
 7829            InlineCompletion::Edit {
 7830                edits,
 7831                edit_preview: inline_completion.edit_preview,
 7832                display_mode,
 7833                snapshot,
 7834            }
 7835        };
 7836
 7837        let invalidation_range = multibuffer
 7838            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7839            ..multibuffer.anchor_after(Point::new(
 7840                invalidation_row_range.end,
 7841                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7842            ));
 7843
 7844        self.stale_inline_completion_in_menu = None;
 7845        self.active_inline_completion = Some(InlineCompletionState {
 7846            inlay_ids,
 7847            completion,
 7848            completion_id: inline_completion.id,
 7849            invalidation_range,
 7850        });
 7851
 7852        cx.notify();
 7853
 7854        Some(())
 7855    }
 7856
 7857    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7858        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7859    }
 7860
 7861    fn clear_tasks(&mut self) {
 7862        self.tasks.clear()
 7863    }
 7864
 7865    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7866        if self.tasks.insert(key, value).is_some() {
 7867            // This case should hopefully be rare, but just in case...
 7868            log::error!(
 7869                "multiple different run targets found on a single line, only the last target will be rendered"
 7870            )
 7871        }
 7872    }
 7873
 7874    /// Get all display points of breakpoints that will be rendered within editor
 7875    ///
 7876    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7877    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7878    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7879    fn active_breakpoints(
 7880        &self,
 7881        range: Range<DisplayRow>,
 7882        window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7885        let mut breakpoint_display_points = HashMap::default();
 7886
 7887        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7888            return breakpoint_display_points;
 7889        };
 7890
 7891        let snapshot = self.snapshot(window, cx);
 7892
 7893        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7894        let Some(project) = self.project.as_ref() else {
 7895            return breakpoint_display_points;
 7896        };
 7897
 7898        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7899            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7900
 7901        for (buffer_snapshot, range, excerpt_id) in
 7902            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7903        {
 7904            let Some(buffer) = project
 7905                .read(cx)
 7906                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7907            else {
 7908                continue;
 7909            };
 7910            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7911                &buffer,
 7912                Some(
 7913                    buffer_snapshot.anchor_before(range.start)
 7914                        ..buffer_snapshot.anchor_after(range.end),
 7915                ),
 7916                buffer_snapshot,
 7917                cx,
 7918            );
 7919            for (breakpoint, state) in breakpoints {
 7920                let multi_buffer_anchor =
 7921                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7922                let position = multi_buffer_anchor
 7923                    .to_point(&multi_buffer_snapshot)
 7924                    .to_display_point(&snapshot);
 7925
 7926                breakpoint_display_points.insert(
 7927                    position.row(),
 7928                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7929                );
 7930            }
 7931        }
 7932
 7933        breakpoint_display_points
 7934    }
 7935
 7936    fn breakpoint_context_menu(
 7937        &self,
 7938        anchor: Anchor,
 7939        window: &mut Window,
 7940        cx: &mut Context<Self>,
 7941    ) -> Entity<ui::ContextMenu> {
 7942        let weak_editor = cx.weak_entity();
 7943        let focus_handle = self.focus_handle(cx);
 7944
 7945        let row = self
 7946            .buffer
 7947            .read(cx)
 7948            .snapshot(cx)
 7949            .summary_for_anchor::<Point>(&anchor)
 7950            .row;
 7951
 7952        let breakpoint = self
 7953            .breakpoint_at_row(row, window, cx)
 7954            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7955
 7956        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7957            "Edit Log Breakpoint"
 7958        } else {
 7959            "Set Log Breakpoint"
 7960        };
 7961
 7962        let condition_breakpoint_msg = if breakpoint
 7963            .as_ref()
 7964            .is_some_and(|bp| bp.1.condition.is_some())
 7965        {
 7966            "Edit Condition Breakpoint"
 7967        } else {
 7968            "Set Condition Breakpoint"
 7969        };
 7970
 7971        let hit_condition_breakpoint_msg = if breakpoint
 7972            .as_ref()
 7973            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7974        {
 7975            "Edit Hit Condition Breakpoint"
 7976        } else {
 7977            "Set Hit Condition Breakpoint"
 7978        };
 7979
 7980        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7981            "Unset Breakpoint"
 7982        } else {
 7983            "Set Breakpoint"
 7984        };
 7985
 7986        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7987
 7988        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7989            BreakpointState::Enabled => Some("Disable"),
 7990            BreakpointState::Disabled => Some("Enable"),
 7991        });
 7992
 7993        let (anchor, breakpoint) =
 7994            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7995
 7996        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7997            menu.on_blur_subscription(Subscription::new(|| {}))
 7998                .context(focus_handle)
 7999                .when(run_to_cursor, |this| {
 8000                    let weak_editor = weak_editor.clone();
 8001                    this.entry("Run to cursor", None, move |window, cx| {
 8002                        weak_editor
 8003                            .update(cx, |editor, cx| {
 8004                                editor.change_selections(
 8005                                    SelectionEffects::no_scroll(),
 8006                                    window,
 8007                                    cx,
 8008                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8009                                );
 8010                            })
 8011                            .ok();
 8012
 8013                        window.dispatch_action(Box::new(RunToCursor), cx);
 8014                    })
 8015                    .separator()
 8016                })
 8017                .when_some(toggle_state_msg, |this, msg| {
 8018                    this.entry(msg, None, {
 8019                        let weak_editor = weak_editor.clone();
 8020                        let breakpoint = breakpoint.clone();
 8021                        move |_window, cx| {
 8022                            weak_editor
 8023                                .update(cx, |this, cx| {
 8024                                    this.edit_breakpoint_at_anchor(
 8025                                        anchor,
 8026                                        breakpoint.as_ref().clone(),
 8027                                        BreakpointEditAction::InvertState,
 8028                                        cx,
 8029                                    );
 8030                                })
 8031                                .log_err();
 8032                        }
 8033                    })
 8034                })
 8035                .entry(set_breakpoint_msg, None, {
 8036                    let weak_editor = weak_editor.clone();
 8037                    let breakpoint = breakpoint.clone();
 8038                    move |_window, cx| {
 8039                        weak_editor
 8040                            .update(cx, |this, cx| {
 8041                                this.edit_breakpoint_at_anchor(
 8042                                    anchor,
 8043                                    breakpoint.as_ref().clone(),
 8044                                    BreakpointEditAction::Toggle,
 8045                                    cx,
 8046                                );
 8047                            })
 8048                            .log_err();
 8049                    }
 8050                })
 8051                .entry(log_breakpoint_msg, None, {
 8052                    let breakpoint = breakpoint.clone();
 8053                    let weak_editor = weak_editor.clone();
 8054                    move |window, cx| {
 8055                        weak_editor
 8056                            .update(cx, |this, cx| {
 8057                                this.add_edit_breakpoint_block(
 8058                                    anchor,
 8059                                    breakpoint.as_ref(),
 8060                                    BreakpointPromptEditAction::Log,
 8061                                    window,
 8062                                    cx,
 8063                                );
 8064                            })
 8065                            .log_err();
 8066                    }
 8067                })
 8068                .entry(condition_breakpoint_msg, None, {
 8069                    let breakpoint = breakpoint.clone();
 8070                    let weak_editor = weak_editor.clone();
 8071                    move |window, cx| {
 8072                        weak_editor
 8073                            .update(cx, |this, cx| {
 8074                                this.add_edit_breakpoint_block(
 8075                                    anchor,
 8076                                    breakpoint.as_ref(),
 8077                                    BreakpointPromptEditAction::Condition,
 8078                                    window,
 8079                                    cx,
 8080                                );
 8081                            })
 8082                            .log_err();
 8083                    }
 8084                })
 8085                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8086                    weak_editor
 8087                        .update(cx, |this, cx| {
 8088                            this.add_edit_breakpoint_block(
 8089                                anchor,
 8090                                breakpoint.as_ref(),
 8091                                BreakpointPromptEditAction::HitCondition,
 8092                                window,
 8093                                cx,
 8094                            );
 8095                        })
 8096                        .log_err();
 8097                })
 8098        })
 8099    }
 8100
 8101    fn render_breakpoint(
 8102        &self,
 8103        position: Anchor,
 8104        row: DisplayRow,
 8105        breakpoint: &Breakpoint,
 8106        state: Option<BreakpointSessionState>,
 8107        cx: &mut Context<Self>,
 8108    ) -> IconButton {
 8109        let is_rejected = state.is_some_and(|s| !s.verified);
 8110        // Is it a breakpoint that shows up when hovering over gutter?
 8111        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8112            (false, false),
 8113            |PhantomBreakpointIndicator {
 8114                 is_active,
 8115                 display_row,
 8116                 collides_with_existing_breakpoint,
 8117             }| {
 8118                (
 8119                    is_active && display_row == row,
 8120                    collides_with_existing_breakpoint,
 8121                )
 8122            },
 8123        );
 8124
 8125        let (color, icon) = {
 8126            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8127                (false, false) => ui::IconName::DebugBreakpoint,
 8128                (true, false) => ui::IconName::DebugLogBreakpoint,
 8129                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8130                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8131            };
 8132
 8133            let color = if is_phantom {
 8134                Color::Hint
 8135            } else if is_rejected {
 8136                Color::Disabled
 8137            } else {
 8138                Color::Debugger
 8139            };
 8140
 8141            (color, icon)
 8142        };
 8143
 8144        let breakpoint = Arc::from(breakpoint.clone());
 8145
 8146        let alt_as_text = gpui::Keystroke {
 8147            modifiers: Modifiers::secondary_key(),
 8148            ..Default::default()
 8149        };
 8150        let primary_action_text = if breakpoint.is_disabled() {
 8151            "Enable breakpoint"
 8152        } else if is_phantom && !collides_with_existing {
 8153            "Set breakpoint"
 8154        } else {
 8155            "Unset breakpoint"
 8156        };
 8157        let focus_handle = self.focus_handle.clone();
 8158
 8159        let meta = if is_rejected {
 8160            SharedString::from("No executable code is associated with this line.")
 8161        } else if collides_with_existing && !breakpoint.is_disabled() {
 8162            SharedString::from(format!(
 8163                "{alt_as_text}-click to disable,\nright-click for more options."
 8164            ))
 8165        } else {
 8166            SharedString::from("Right-click for more options.")
 8167        };
 8168        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8169            .icon_size(IconSize::XSmall)
 8170            .size(ui::ButtonSize::None)
 8171            .when(is_rejected, |this| {
 8172                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8173            })
 8174            .icon_color(color)
 8175            .style(ButtonStyle::Transparent)
 8176            .on_click(cx.listener({
 8177                let breakpoint = breakpoint.clone();
 8178
 8179                move |editor, event: &ClickEvent, window, cx| {
 8180                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8181                        BreakpointEditAction::InvertState
 8182                    } else {
 8183                        BreakpointEditAction::Toggle
 8184                    };
 8185
 8186                    window.focus(&editor.focus_handle(cx));
 8187                    editor.edit_breakpoint_at_anchor(
 8188                        position,
 8189                        breakpoint.as_ref().clone(),
 8190                        edit_action,
 8191                        cx,
 8192                    );
 8193                }
 8194            }))
 8195            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8196                editor.set_breakpoint_context_menu(
 8197                    row,
 8198                    Some(position),
 8199                    event.down.position,
 8200                    window,
 8201                    cx,
 8202                );
 8203            }))
 8204            .tooltip(move |window, cx| {
 8205                Tooltip::with_meta_in(
 8206                    primary_action_text,
 8207                    Some(&ToggleBreakpoint),
 8208                    meta.clone(),
 8209                    &focus_handle,
 8210                    window,
 8211                    cx,
 8212                )
 8213            })
 8214    }
 8215
 8216    fn build_tasks_context(
 8217        project: &Entity<Project>,
 8218        buffer: &Entity<Buffer>,
 8219        buffer_row: u32,
 8220        tasks: &Arc<RunnableTasks>,
 8221        cx: &mut Context<Self>,
 8222    ) -> Task<Option<task::TaskContext>> {
 8223        let position = Point::new(buffer_row, tasks.column);
 8224        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8225        let location = Location {
 8226            buffer: buffer.clone(),
 8227            range: range_start..range_start,
 8228        };
 8229        // Fill in the environmental variables from the tree-sitter captures
 8230        let mut captured_task_variables = TaskVariables::default();
 8231        for (capture_name, value) in tasks.extra_variables.clone() {
 8232            captured_task_variables.insert(
 8233                task::VariableName::Custom(capture_name.into()),
 8234                value.clone(),
 8235            );
 8236        }
 8237        project.update(cx, |project, cx| {
 8238            project.task_store().update(cx, |task_store, cx| {
 8239                task_store.task_context_for_location(captured_task_variables, location, cx)
 8240            })
 8241        })
 8242    }
 8243
 8244    pub fn spawn_nearest_task(
 8245        &mut self,
 8246        action: &SpawnNearestTask,
 8247        window: &mut Window,
 8248        cx: &mut Context<Self>,
 8249    ) {
 8250        let Some((workspace, _)) = self.workspace.clone() else {
 8251            return;
 8252        };
 8253        let Some(project) = self.project.clone() else {
 8254            return;
 8255        };
 8256
 8257        // Try to find a closest, enclosing node using tree-sitter that has a task
 8258        let Some((buffer, buffer_row, tasks)) = self
 8259            .find_enclosing_node_task(cx)
 8260            // Or find the task that's closest in row-distance.
 8261            .or_else(|| self.find_closest_task(cx))
 8262        else {
 8263            return;
 8264        };
 8265
 8266        let reveal_strategy = action.reveal;
 8267        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8268        cx.spawn_in(window, async move |_, cx| {
 8269            let context = task_context.await?;
 8270            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8271
 8272            let resolved = &mut resolved_task.resolved;
 8273            resolved.reveal = reveal_strategy;
 8274
 8275            workspace
 8276                .update_in(cx, |workspace, window, cx| {
 8277                    workspace.schedule_resolved_task(
 8278                        task_source_kind,
 8279                        resolved_task,
 8280                        false,
 8281                        window,
 8282                        cx,
 8283                    );
 8284                })
 8285                .ok()
 8286        })
 8287        .detach();
 8288    }
 8289
 8290    fn find_closest_task(
 8291        &mut self,
 8292        cx: &mut Context<Self>,
 8293    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8294        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8295
 8296        let ((buffer_id, row), tasks) = self
 8297            .tasks
 8298            .iter()
 8299            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8300
 8301        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8302        let tasks = Arc::new(tasks.to_owned());
 8303        Some((buffer, *row, tasks))
 8304    }
 8305
 8306    fn find_enclosing_node_task(
 8307        &mut self,
 8308        cx: &mut Context<Self>,
 8309    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8310        let snapshot = self.buffer.read(cx).snapshot(cx);
 8311        let offset = self.selections.newest::<usize>(cx).head();
 8312        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8313        let buffer_id = excerpt.buffer().remote_id();
 8314
 8315        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8316        let mut cursor = layer.node().walk();
 8317
 8318        while cursor.goto_first_child_for_byte(offset).is_some() {
 8319            if cursor.node().end_byte() == offset {
 8320                cursor.goto_next_sibling();
 8321            }
 8322        }
 8323
 8324        // Ascend to the smallest ancestor that contains the range and has a task.
 8325        loop {
 8326            let node = cursor.node();
 8327            let node_range = node.byte_range();
 8328            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8329
 8330            // Check if this node contains our offset
 8331            if node_range.start <= offset && node_range.end >= offset {
 8332                // If it contains offset, check for task
 8333                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8334                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8335                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8336                }
 8337            }
 8338
 8339            if !cursor.goto_parent() {
 8340                break;
 8341            }
 8342        }
 8343        None
 8344    }
 8345
 8346    fn render_run_indicator(
 8347        &self,
 8348        _style: &EditorStyle,
 8349        is_active: bool,
 8350        row: DisplayRow,
 8351        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8352        cx: &mut Context<Self>,
 8353    ) -> IconButton {
 8354        let color = Color::Muted;
 8355        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8356
 8357        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8358            .shape(ui::IconButtonShape::Square)
 8359            .icon_size(IconSize::XSmall)
 8360            .icon_color(color)
 8361            .toggle_state(is_active)
 8362            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8363                let quick_launch = e.down.button == MouseButton::Left;
 8364                window.focus(&editor.focus_handle(cx));
 8365                editor.toggle_code_actions(
 8366                    &ToggleCodeActions {
 8367                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8368                        quick_launch,
 8369                    },
 8370                    window,
 8371                    cx,
 8372                );
 8373            }))
 8374            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8375                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8376            }))
 8377    }
 8378
 8379    pub fn context_menu_visible(&self) -> bool {
 8380        !self.edit_prediction_preview_is_active()
 8381            && self
 8382                .context_menu
 8383                .borrow()
 8384                .as_ref()
 8385                .map_or(false, |menu| menu.visible())
 8386    }
 8387
 8388    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8389        self.context_menu
 8390            .borrow()
 8391            .as_ref()
 8392            .map(|menu| menu.origin())
 8393    }
 8394
 8395    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8396        self.context_menu_options = Some(options);
 8397    }
 8398
 8399    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8400    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8401
 8402    fn render_edit_prediction_popover(
 8403        &mut self,
 8404        text_bounds: &Bounds<Pixels>,
 8405        content_origin: gpui::Point<Pixels>,
 8406        right_margin: Pixels,
 8407        editor_snapshot: &EditorSnapshot,
 8408        visible_row_range: Range<DisplayRow>,
 8409        scroll_top: f32,
 8410        scroll_bottom: f32,
 8411        line_layouts: &[LineWithInvisibles],
 8412        line_height: Pixels,
 8413        scroll_pixel_position: gpui::Point<Pixels>,
 8414        newest_selection_head: Option<DisplayPoint>,
 8415        editor_width: Pixels,
 8416        style: &EditorStyle,
 8417        window: &mut Window,
 8418        cx: &mut App,
 8419    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8420        if self.mode().is_minimap() {
 8421            return None;
 8422        }
 8423        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8424
 8425        if self.edit_prediction_visible_in_cursor_popover(true) {
 8426            return None;
 8427        }
 8428
 8429        match &active_inline_completion.completion {
 8430            InlineCompletion::Move { target, .. } => {
 8431                let target_display_point = target.to_display_point(editor_snapshot);
 8432
 8433                if self.edit_prediction_requires_modifier() {
 8434                    if !self.edit_prediction_preview_is_active() {
 8435                        return None;
 8436                    }
 8437
 8438                    self.render_edit_prediction_modifier_jump_popover(
 8439                        text_bounds,
 8440                        content_origin,
 8441                        visible_row_range,
 8442                        line_layouts,
 8443                        line_height,
 8444                        scroll_pixel_position,
 8445                        newest_selection_head,
 8446                        target_display_point,
 8447                        window,
 8448                        cx,
 8449                    )
 8450                } else {
 8451                    self.render_edit_prediction_eager_jump_popover(
 8452                        text_bounds,
 8453                        content_origin,
 8454                        editor_snapshot,
 8455                        visible_row_range,
 8456                        scroll_top,
 8457                        scroll_bottom,
 8458                        line_height,
 8459                        scroll_pixel_position,
 8460                        target_display_point,
 8461                        editor_width,
 8462                        window,
 8463                        cx,
 8464                    )
 8465                }
 8466            }
 8467            InlineCompletion::Edit {
 8468                display_mode: EditDisplayMode::Inline,
 8469                ..
 8470            } => None,
 8471            InlineCompletion::Edit {
 8472                display_mode: EditDisplayMode::TabAccept,
 8473                edits,
 8474                ..
 8475            } => {
 8476                let range = &edits.first()?.0;
 8477                let target_display_point = range.end.to_display_point(editor_snapshot);
 8478
 8479                self.render_edit_prediction_end_of_line_popover(
 8480                    "Accept",
 8481                    editor_snapshot,
 8482                    visible_row_range,
 8483                    target_display_point,
 8484                    line_height,
 8485                    scroll_pixel_position,
 8486                    content_origin,
 8487                    editor_width,
 8488                    window,
 8489                    cx,
 8490                )
 8491            }
 8492            InlineCompletion::Edit {
 8493                edits,
 8494                edit_preview,
 8495                display_mode: EditDisplayMode::DiffPopover,
 8496                snapshot,
 8497            } => self.render_edit_prediction_diff_popover(
 8498                text_bounds,
 8499                content_origin,
 8500                right_margin,
 8501                editor_snapshot,
 8502                visible_row_range,
 8503                line_layouts,
 8504                line_height,
 8505                scroll_pixel_position,
 8506                newest_selection_head,
 8507                editor_width,
 8508                style,
 8509                edits,
 8510                edit_preview,
 8511                snapshot,
 8512                window,
 8513                cx,
 8514            ),
 8515        }
 8516    }
 8517
 8518    fn render_edit_prediction_modifier_jump_popover(
 8519        &mut self,
 8520        text_bounds: &Bounds<Pixels>,
 8521        content_origin: gpui::Point<Pixels>,
 8522        visible_row_range: Range<DisplayRow>,
 8523        line_layouts: &[LineWithInvisibles],
 8524        line_height: Pixels,
 8525        scroll_pixel_position: gpui::Point<Pixels>,
 8526        newest_selection_head: Option<DisplayPoint>,
 8527        target_display_point: DisplayPoint,
 8528        window: &mut Window,
 8529        cx: &mut App,
 8530    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8531        let scrolled_content_origin =
 8532            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8533
 8534        const SCROLL_PADDING_Y: Pixels = px(12.);
 8535
 8536        if target_display_point.row() < visible_row_range.start {
 8537            return self.render_edit_prediction_scroll_popover(
 8538                |_| SCROLL_PADDING_Y,
 8539                IconName::ArrowUp,
 8540                visible_row_range,
 8541                line_layouts,
 8542                newest_selection_head,
 8543                scrolled_content_origin,
 8544                window,
 8545                cx,
 8546            );
 8547        } else if target_display_point.row() >= visible_row_range.end {
 8548            return self.render_edit_prediction_scroll_popover(
 8549                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8550                IconName::ArrowDown,
 8551                visible_row_range,
 8552                line_layouts,
 8553                newest_selection_head,
 8554                scrolled_content_origin,
 8555                window,
 8556                cx,
 8557            );
 8558        }
 8559
 8560        const POLE_WIDTH: Pixels = px(2.);
 8561
 8562        let line_layout =
 8563            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8564        let target_column = target_display_point.column() as usize;
 8565
 8566        let target_x = line_layout.x_for_index(target_column);
 8567        let target_y =
 8568            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8569
 8570        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8571
 8572        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8573        border_color.l += 0.001;
 8574
 8575        let mut element = v_flex()
 8576            .items_end()
 8577            .when(flag_on_right, |el| el.items_start())
 8578            .child(if flag_on_right {
 8579                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8580                    .rounded_bl(px(0.))
 8581                    .rounded_tl(px(0.))
 8582                    .border_l_2()
 8583                    .border_color(border_color)
 8584            } else {
 8585                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8586                    .rounded_br(px(0.))
 8587                    .rounded_tr(px(0.))
 8588                    .border_r_2()
 8589                    .border_color(border_color)
 8590            })
 8591            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8592            .into_any();
 8593
 8594        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8595
 8596        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8597            - point(
 8598                if flag_on_right {
 8599                    POLE_WIDTH
 8600                } else {
 8601                    size.width - POLE_WIDTH
 8602                },
 8603                size.height - line_height,
 8604            );
 8605
 8606        origin.x = origin.x.max(content_origin.x);
 8607
 8608        element.prepaint_at(origin, window, cx);
 8609
 8610        Some((element, origin))
 8611    }
 8612
 8613    fn render_edit_prediction_scroll_popover(
 8614        &mut self,
 8615        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8616        scroll_icon: IconName,
 8617        visible_row_range: Range<DisplayRow>,
 8618        line_layouts: &[LineWithInvisibles],
 8619        newest_selection_head: Option<DisplayPoint>,
 8620        scrolled_content_origin: gpui::Point<Pixels>,
 8621        window: &mut Window,
 8622        cx: &mut App,
 8623    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8624        let mut element = self
 8625            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8626            .into_any();
 8627
 8628        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8629
 8630        let cursor = newest_selection_head?;
 8631        let cursor_row_layout =
 8632            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8633        let cursor_column = cursor.column() as usize;
 8634
 8635        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8636
 8637        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8638
 8639        element.prepaint_at(origin, window, cx);
 8640        Some((element, origin))
 8641    }
 8642
 8643    fn render_edit_prediction_eager_jump_popover(
 8644        &mut self,
 8645        text_bounds: &Bounds<Pixels>,
 8646        content_origin: gpui::Point<Pixels>,
 8647        editor_snapshot: &EditorSnapshot,
 8648        visible_row_range: Range<DisplayRow>,
 8649        scroll_top: f32,
 8650        scroll_bottom: f32,
 8651        line_height: Pixels,
 8652        scroll_pixel_position: gpui::Point<Pixels>,
 8653        target_display_point: DisplayPoint,
 8654        editor_width: Pixels,
 8655        window: &mut Window,
 8656        cx: &mut App,
 8657    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8658        if target_display_point.row().as_f32() < scroll_top {
 8659            let mut element = self
 8660                .render_edit_prediction_line_popover(
 8661                    "Jump to Edit",
 8662                    Some(IconName::ArrowUp),
 8663                    window,
 8664                    cx,
 8665                )?
 8666                .into_any();
 8667
 8668            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8669            let offset = point(
 8670                (text_bounds.size.width - size.width) / 2.,
 8671                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8672            );
 8673
 8674            let origin = text_bounds.origin + offset;
 8675            element.prepaint_at(origin, window, cx);
 8676            Some((element, origin))
 8677        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8678            let mut element = self
 8679                .render_edit_prediction_line_popover(
 8680                    "Jump to Edit",
 8681                    Some(IconName::ArrowDown),
 8682                    window,
 8683                    cx,
 8684                )?
 8685                .into_any();
 8686
 8687            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8688            let offset = point(
 8689                (text_bounds.size.width - size.width) / 2.,
 8690                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8691            );
 8692
 8693            let origin = text_bounds.origin + offset;
 8694            element.prepaint_at(origin, window, cx);
 8695            Some((element, origin))
 8696        } else {
 8697            self.render_edit_prediction_end_of_line_popover(
 8698                "Jump to Edit",
 8699                editor_snapshot,
 8700                visible_row_range,
 8701                target_display_point,
 8702                line_height,
 8703                scroll_pixel_position,
 8704                content_origin,
 8705                editor_width,
 8706                window,
 8707                cx,
 8708            )
 8709        }
 8710    }
 8711
 8712    fn render_edit_prediction_end_of_line_popover(
 8713        self: &mut Editor,
 8714        label: &'static str,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        target_display_point: DisplayPoint,
 8718        line_height: Pixels,
 8719        scroll_pixel_position: gpui::Point<Pixels>,
 8720        content_origin: gpui::Point<Pixels>,
 8721        editor_width: Pixels,
 8722        window: &mut Window,
 8723        cx: &mut App,
 8724    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8725        let target_line_end = DisplayPoint::new(
 8726            target_display_point.row(),
 8727            editor_snapshot.line_len(target_display_point.row()),
 8728        );
 8729
 8730        let mut element = self
 8731            .render_edit_prediction_line_popover(label, None, window, cx)?
 8732            .into_any();
 8733
 8734        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8735
 8736        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8737
 8738        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8739        let mut origin = start_point
 8740            + line_origin
 8741            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8742        origin.x = origin.x.max(content_origin.x);
 8743
 8744        let max_x = content_origin.x + editor_width - size.width;
 8745
 8746        if origin.x > max_x {
 8747            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8748
 8749            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8750                origin.y += offset;
 8751                IconName::ArrowUp
 8752            } else {
 8753                origin.y -= offset;
 8754                IconName::ArrowDown
 8755            };
 8756
 8757            element = self
 8758                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762
 8763            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8764        }
 8765
 8766        element.prepaint_at(origin, window, cx);
 8767        Some((element, origin))
 8768    }
 8769
 8770    fn render_edit_prediction_diff_popover(
 8771        self: &Editor,
 8772        text_bounds: &Bounds<Pixels>,
 8773        content_origin: gpui::Point<Pixels>,
 8774        right_margin: Pixels,
 8775        editor_snapshot: &EditorSnapshot,
 8776        visible_row_range: Range<DisplayRow>,
 8777        line_layouts: &[LineWithInvisibles],
 8778        line_height: Pixels,
 8779        scroll_pixel_position: gpui::Point<Pixels>,
 8780        newest_selection_head: Option<DisplayPoint>,
 8781        editor_width: Pixels,
 8782        style: &EditorStyle,
 8783        edits: &Vec<(Range<Anchor>, String)>,
 8784        edit_preview: &Option<language::EditPreview>,
 8785        snapshot: &language::BufferSnapshot,
 8786        window: &mut Window,
 8787        cx: &mut App,
 8788    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8789        let edit_start = edits
 8790            .first()
 8791            .unwrap()
 8792            .0
 8793            .start
 8794            .to_display_point(editor_snapshot);
 8795        let edit_end = edits
 8796            .last()
 8797            .unwrap()
 8798            .0
 8799            .end
 8800            .to_display_point(editor_snapshot);
 8801
 8802        let is_visible = visible_row_range.contains(&edit_start.row())
 8803            || visible_row_range.contains(&edit_end.row());
 8804        if !is_visible {
 8805            return None;
 8806        }
 8807
 8808        let highlighted_edits =
 8809            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8810
 8811        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8812        let line_count = highlighted_edits.text.lines().count();
 8813
 8814        const BORDER_WIDTH: Pixels = px(1.);
 8815
 8816        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8817        let has_keybind = keybind.is_some();
 8818
 8819        let mut element = h_flex()
 8820            .items_start()
 8821            .child(
 8822                h_flex()
 8823                    .bg(cx.theme().colors().editor_background)
 8824                    .border(BORDER_WIDTH)
 8825                    .shadow_xs()
 8826                    .border_color(cx.theme().colors().border)
 8827                    .rounded_l_lg()
 8828                    .when(line_count > 1, |el| el.rounded_br_lg())
 8829                    .pr_1()
 8830                    .child(styled_text),
 8831            )
 8832            .child(
 8833                h_flex()
 8834                    .h(line_height + BORDER_WIDTH * 2.)
 8835                    .px_1p5()
 8836                    .gap_1()
 8837                    // Workaround: For some reason, there's a gap if we don't do this
 8838                    .ml(-BORDER_WIDTH)
 8839                    .shadow(vec![gpui::BoxShadow {
 8840                        color: gpui::black().opacity(0.05),
 8841                        offset: point(px(1.), px(1.)),
 8842                        blur_radius: px(2.),
 8843                        spread_radius: px(0.),
 8844                    }])
 8845                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8846                    .border(BORDER_WIDTH)
 8847                    .border_color(cx.theme().colors().border)
 8848                    .rounded_r_lg()
 8849                    .id("edit_prediction_diff_popover_keybind")
 8850                    .when(!has_keybind, |el| {
 8851                        let status_colors = cx.theme().status();
 8852
 8853                        el.bg(status_colors.error_background)
 8854                            .border_color(status_colors.error.opacity(0.6))
 8855                            .child(Icon::new(IconName::Info).color(Color::Error))
 8856                            .cursor_default()
 8857                            .hoverable_tooltip(move |_window, cx| {
 8858                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8859                            })
 8860                    })
 8861                    .children(keybind),
 8862            )
 8863            .into_any();
 8864
 8865        let longest_row =
 8866            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8867        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8868            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8869        } else {
 8870            layout_line(
 8871                longest_row,
 8872                editor_snapshot,
 8873                style,
 8874                editor_width,
 8875                |_| false,
 8876                window,
 8877                cx,
 8878            )
 8879            .width
 8880        };
 8881
 8882        let viewport_bounds =
 8883            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8884                right: -right_margin,
 8885                ..Default::default()
 8886            });
 8887
 8888        let x_after_longest =
 8889            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8890                - scroll_pixel_position.x;
 8891
 8892        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8893
 8894        // Fully visible if it can be displayed within the window (allow overlapping other
 8895        // panes). However, this is only allowed if the popover starts within text_bounds.
 8896        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8897            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8898
 8899        let mut origin = if can_position_to_the_right {
 8900            point(
 8901                x_after_longest,
 8902                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8903                    - scroll_pixel_position.y,
 8904            )
 8905        } else {
 8906            let cursor_row = newest_selection_head.map(|head| head.row());
 8907            let above_edit = edit_start
 8908                .row()
 8909                .0
 8910                .checked_sub(line_count as u32)
 8911                .map(DisplayRow);
 8912            let below_edit = Some(edit_end.row() + 1);
 8913            let above_cursor =
 8914                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8915            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8916
 8917            // Place the edit popover adjacent to the edit if there is a location
 8918            // available that is onscreen and does not obscure the cursor. Otherwise,
 8919            // place it adjacent to the cursor.
 8920            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8921                .into_iter()
 8922                .flatten()
 8923                .find(|&start_row| {
 8924                    let end_row = start_row + line_count as u32;
 8925                    visible_row_range.contains(&start_row)
 8926                        && visible_row_range.contains(&end_row)
 8927                        && cursor_row.map_or(true, |cursor_row| {
 8928                            !((start_row..end_row).contains(&cursor_row))
 8929                        })
 8930                })?;
 8931
 8932            content_origin
 8933                + point(
 8934                    -scroll_pixel_position.x,
 8935                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8936                )
 8937        };
 8938
 8939        origin.x -= BORDER_WIDTH;
 8940
 8941        window.defer_draw(element, origin, 1);
 8942
 8943        // Do not return an element, since it will already be drawn due to defer_draw.
 8944        None
 8945    }
 8946
 8947    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8948        px(30.)
 8949    }
 8950
 8951    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8952        if self.read_only(cx) {
 8953            cx.theme().players().read_only()
 8954        } else {
 8955            self.style.as_ref().unwrap().local_player
 8956        }
 8957    }
 8958
 8959    fn render_edit_prediction_accept_keybind(
 8960        &self,
 8961        window: &mut Window,
 8962        cx: &App,
 8963    ) -> Option<AnyElement> {
 8964        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8965        let accept_keystroke = accept_binding.keystroke()?;
 8966
 8967        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8968
 8969        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8970            Color::Accent
 8971        } else {
 8972            Color::Muted
 8973        };
 8974
 8975        h_flex()
 8976            .px_0p5()
 8977            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8978            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8979            .text_size(TextSize::XSmall.rems(cx))
 8980            .child(h_flex().children(ui::render_modifiers(
 8981                &accept_keystroke.modifiers,
 8982                PlatformStyle::platform(),
 8983                Some(modifiers_color),
 8984                Some(IconSize::XSmall.rems().into()),
 8985                true,
 8986            )))
 8987            .when(is_platform_style_mac, |parent| {
 8988                parent.child(accept_keystroke.key.clone())
 8989            })
 8990            .when(!is_platform_style_mac, |parent| {
 8991                parent.child(
 8992                    Key::new(
 8993                        util::capitalize(&accept_keystroke.key),
 8994                        Some(Color::Default),
 8995                    )
 8996                    .size(Some(IconSize::XSmall.rems().into())),
 8997                )
 8998            })
 8999            .into_any()
 9000            .into()
 9001    }
 9002
 9003    fn render_edit_prediction_line_popover(
 9004        &self,
 9005        label: impl Into<SharedString>,
 9006        icon: Option<IconName>,
 9007        window: &mut Window,
 9008        cx: &App,
 9009    ) -> Option<Stateful<Div>> {
 9010        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9011
 9012        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9013        let has_keybind = keybind.is_some();
 9014
 9015        let result = h_flex()
 9016            .id("ep-line-popover")
 9017            .py_0p5()
 9018            .pl_1()
 9019            .pr(padding_right)
 9020            .gap_1()
 9021            .rounded_md()
 9022            .border_1()
 9023            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9024            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9025            .shadow_xs()
 9026            .when(!has_keybind, |el| {
 9027                let status_colors = cx.theme().status();
 9028
 9029                el.bg(status_colors.error_background)
 9030                    .border_color(status_colors.error.opacity(0.6))
 9031                    .pl_2()
 9032                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9033                    .cursor_default()
 9034                    .hoverable_tooltip(move |_window, cx| {
 9035                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9036                    })
 9037            })
 9038            .children(keybind)
 9039            .child(
 9040                Label::new(label)
 9041                    .size(LabelSize::Small)
 9042                    .when(!has_keybind, |el| {
 9043                        el.color(cx.theme().status().error.into()).strikethrough()
 9044                    }),
 9045            )
 9046            .when(!has_keybind, |el| {
 9047                el.child(
 9048                    h_flex().ml_1().child(
 9049                        Icon::new(IconName::Info)
 9050                            .size(IconSize::Small)
 9051                            .color(cx.theme().status().error.into()),
 9052                    ),
 9053                )
 9054            })
 9055            .when_some(icon, |element, icon| {
 9056                element.child(
 9057                    div()
 9058                        .mt(px(1.5))
 9059                        .child(Icon::new(icon).size(IconSize::Small)),
 9060                )
 9061            });
 9062
 9063        Some(result)
 9064    }
 9065
 9066    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9067        let accent_color = cx.theme().colors().text_accent;
 9068        let editor_bg_color = cx.theme().colors().editor_background;
 9069        editor_bg_color.blend(accent_color.opacity(0.1))
 9070    }
 9071
 9072    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9073        let accent_color = cx.theme().colors().text_accent;
 9074        let editor_bg_color = cx.theme().colors().editor_background;
 9075        editor_bg_color.blend(accent_color.opacity(0.6))
 9076    }
 9077
 9078    fn render_edit_prediction_cursor_popover(
 9079        &self,
 9080        min_width: Pixels,
 9081        max_width: Pixels,
 9082        cursor_point: Point,
 9083        style: &EditorStyle,
 9084        accept_keystroke: Option<&gpui::Keystroke>,
 9085        _window: &Window,
 9086        cx: &mut Context<Editor>,
 9087    ) -> Option<AnyElement> {
 9088        let provider = self.edit_prediction_provider.as_ref()?;
 9089
 9090        if provider.provider.needs_terms_acceptance(cx) {
 9091            return Some(
 9092                h_flex()
 9093                    .min_w(min_width)
 9094                    .flex_1()
 9095                    .px_2()
 9096                    .py_1()
 9097                    .gap_3()
 9098                    .elevation_2(cx)
 9099                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9100                    .id("accept-terms")
 9101                    .cursor_pointer()
 9102                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9103                    .on_click(cx.listener(|this, _event, window, cx| {
 9104                        cx.stop_propagation();
 9105                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9106                        window.dispatch_action(
 9107                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9108                            cx,
 9109                        );
 9110                    }))
 9111                    .child(
 9112                        h_flex()
 9113                            .flex_1()
 9114                            .gap_2()
 9115                            .child(Icon::new(IconName::ZedPredict))
 9116                            .child(Label::new("Accept Terms of Service"))
 9117                            .child(div().w_full())
 9118                            .child(
 9119                                Icon::new(IconName::ArrowUpRight)
 9120                                    .color(Color::Muted)
 9121                                    .size(IconSize::Small),
 9122                            )
 9123                            .into_any_element(),
 9124                    )
 9125                    .into_any(),
 9126            );
 9127        }
 9128
 9129        let is_refreshing = provider.provider.is_refreshing(cx);
 9130
 9131        fn pending_completion_container() -> Div {
 9132            h_flex()
 9133                .h_full()
 9134                .flex_1()
 9135                .gap_2()
 9136                .child(Icon::new(IconName::ZedPredict))
 9137        }
 9138
 9139        let completion = match &self.active_inline_completion {
 9140            Some(prediction) => {
 9141                if !self.has_visible_completions_menu() {
 9142                    const RADIUS: Pixels = px(6.);
 9143                    const BORDER_WIDTH: Pixels = px(1.);
 9144
 9145                    return Some(
 9146                        h_flex()
 9147                            .elevation_2(cx)
 9148                            .border(BORDER_WIDTH)
 9149                            .border_color(cx.theme().colors().border)
 9150                            .when(accept_keystroke.is_none(), |el| {
 9151                                el.border_color(cx.theme().status().error)
 9152                            })
 9153                            .rounded(RADIUS)
 9154                            .rounded_tl(px(0.))
 9155                            .overflow_hidden()
 9156                            .child(div().px_1p5().child(match &prediction.completion {
 9157                                InlineCompletion::Move { target, snapshot } => {
 9158                                    use text::ToPoint as _;
 9159                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9160                                    {
 9161                                        Icon::new(IconName::ZedPredictDown)
 9162                                    } else {
 9163                                        Icon::new(IconName::ZedPredictUp)
 9164                                    }
 9165                                }
 9166                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9167                            }))
 9168                            .child(
 9169                                h_flex()
 9170                                    .gap_1()
 9171                                    .py_1()
 9172                                    .px_2()
 9173                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9174                                    .border_l_1()
 9175                                    .border_color(cx.theme().colors().border)
 9176                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9177                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9178                                        el.child(
 9179                                            Label::new("Hold")
 9180                                                .size(LabelSize::Small)
 9181                                                .when(accept_keystroke.is_none(), |el| {
 9182                                                    el.strikethrough()
 9183                                                })
 9184                                                .line_height_style(LineHeightStyle::UiLabel),
 9185                                        )
 9186                                    })
 9187                                    .id("edit_prediction_cursor_popover_keybind")
 9188                                    .when(accept_keystroke.is_none(), |el| {
 9189                                        let status_colors = cx.theme().status();
 9190
 9191                                        el.bg(status_colors.error_background)
 9192                                            .border_color(status_colors.error.opacity(0.6))
 9193                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9194                                            .cursor_default()
 9195                                            .hoverable_tooltip(move |_window, cx| {
 9196                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9197                                                    .into()
 9198                                            })
 9199                                    })
 9200                                    .when_some(
 9201                                        accept_keystroke.as_ref(),
 9202                                        |el, accept_keystroke| {
 9203                                            el.child(h_flex().children(ui::render_modifiers(
 9204                                                &accept_keystroke.modifiers,
 9205                                                PlatformStyle::platform(),
 9206                                                Some(Color::Default),
 9207                                                Some(IconSize::XSmall.rems().into()),
 9208                                                false,
 9209                                            )))
 9210                                        },
 9211                                    ),
 9212                            )
 9213                            .into_any(),
 9214                    );
 9215                }
 9216
 9217                self.render_edit_prediction_cursor_popover_preview(
 9218                    prediction,
 9219                    cursor_point,
 9220                    style,
 9221                    cx,
 9222                )?
 9223            }
 9224
 9225            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9226                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9227                    stale_completion,
 9228                    cursor_point,
 9229                    style,
 9230                    cx,
 9231                )?,
 9232
 9233                None => {
 9234                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9235                }
 9236            },
 9237
 9238            None => pending_completion_container().child(Label::new("No Prediction")),
 9239        };
 9240
 9241        let completion = if is_refreshing {
 9242            completion
 9243                .with_animation(
 9244                    "loading-completion",
 9245                    Animation::new(Duration::from_secs(2))
 9246                        .repeat()
 9247                        .with_easing(pulsating_between(0.4, 0.8)),
 9248                    |label, delta| label.opacity(delta),
 9249                )
 9250                .into_any_element()
 9251        } else {
 9252            completion.into_any_element()
 9253        };
 9254
 9255        let has_completion = self.active_inline_completion.is_some();
 9256
 9257        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9258        Some(
 9259            h_flex()
 9260                .min_w(min_width)
 9261                .max_w(max_width)
 9262                .flex_1()
 9263                .elevation_2(cx)
 9264                .border_color(cx.theme().colors().border)
 9265                .child(
 9266                    div()
 9267                        .flex_1()
 9268                        .py_1()
 9269                        .px_2()
 9270                        .overflow_hidden()
 9271                        .child(completion),
 9272                )
 9273                .when_some(accept_keystroke, |el, accept_keystroke| {
 9274                    if !accept_keystroke.modifiers.modified() {
 9275                        return el;
 9276                    }
 9277
 9278                    el.child(
 9279                        h_flex()
 9280                            .h_full()
 9281                            .border_l_1()
 9282                            .rounded_r_lg()
 9283                            .border_color(cx.theme().colors().border)
 9284                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9285                            .gap_1()
 9286                            .py_1()
 9287                            .px_2()
 9288                            .child(
 9289                                h_flex()
 9290                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9291                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9292                                    .child(h_flex().children(ui::render_modifiers(
 9293                                        &accept_keystroke.modifiers,
 9294                                        PlatformStyle::platform(),
 9295                                        Some(if !has_completion {
 9296                                            Color::Muted
 9297                                        } else {
 9298                                            Color::Default
 9299                                        }),
 9300                                        None,
 9301                                        false,
 9302                                    ))),
 9303                            )
 9304                            .child(Label::new("Preview").into_any_element())
 9305                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9306                    )
 9307                })
 9308                .into_any(),
 9309        )
 9310    }
 9311
 9312    fn render_edit_prediction_cursor_popover_preview(
 9313        &self,
 9314        completion: &InlineCompletionState,
 9315        cursor_point: Point,
 9316        style: &EditorStyle,
 9317        cx: &mut Context<Editor>,
 9318    ) -> Option<Div> {
 9319        use text::ToPoint as _;
 9320
 9321        fn render_relative_row_jump(
 9322            prefix: impl Into<String>,
 9323            current_row: u32,
 9324            target_row: u32,
 9325        ) -> Div {
 9326            let (row_diff, arrow) = if target_row < current_row {
 9327                (current_row - target_row, IconName::ArrowUp)
 9328            } else {
 9329                (target_row - current_row, IconName::ArrowDown)
 9330            };
 9331
 9332            h_flex()
 9333                .child(
 9334                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9335                        .color(Color::Muted)
 9336                        .size(LabelSize::Small),
 9337                )
 9338                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9339        }
 9340
 9341        match &completion.completion {
 9342            InlineCompletion::Move {
 9343                target, snapshot, ..
 9344            } => Some(
 9345                h_flex()
 9346                    .px_2()
 9347                    .gap_2()
 9348                    .flex_1()
 9349                    .child(
 9350                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9351                            Icon::new(IconName::ZedPredictDown)
 9352                        } else {
 9353                            Icon::new(IconName::ZedPredictUp)
 9354                        },
 9355                    )
 9356                    .child(Label::new("Jump to Edit")),
 9357            ),
 9358
 9359            InlineCompletion::Edit {
 9360                edits,
 9361                edit_preview,
 9362                snapshot,
 9363                display_mode: _,
 9364            } => {
 9365                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9366
 9367                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9368                    &snapshot,
 9369                    &edits,
 9370                    edit_preview.as_ref()?,
 9371                    true,
 9372                    cx,
 9373                )
 9374                .first_line_preview();
 9375
 9376                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9377                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9378
 9379                let preview = h_flex()
 9380                    .gap_1()
 9381                    .min_w_16()
 9382                    .child(styled_text)
 9383                    .when(has_more_lines, |parent| parent.child(""));
 9384
 9385                let left = if first_edit_row != cursor_point.row {
 9386                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9387                        .into_any_element()
 9388                } else {
 9389                    Icon::new(IconName::ZedPredict).into_any_element()
 9390                };
 9391
 9392                Some(
 9393                    h_flex()
 9394                        .h_full()
 9395                        .flex_1()
 9396                        .gap_2()
 9397                        .pr_1()
 9398                        .overflow_x_hidden()
 9399                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9400                        .child(left)
 9401                        .child(preview),
 9402                )
 9403            }
 9404        }
 9405    }
 9406
 9407    pub fn render_context_menu(
 9408        &self,
 9409        style: &EditorStyle,
 9410        max_height_in_lines: u32,
 9411        window: &mut Window,
 9412        cx: &mut Context<Editor>,
 9413    ) -> Option<AnyElement> {
 9414        let menu = self.context_menu.borrow();
 9415        let menu = menu.as_ref()?;
 9416        if !menu.visible() {
 9417            return None;
 9418        };
 9419        Some(menu.render(style, max_height_in_lines, window, cx))
 9420    }
 9421
 9422    fn render_context_menu_aside(
 9423        &mut self,
 9424        max_size: Size<Pixels>,
 9425        window: &mut Window,
 9426        cx: &mut Context<Editor>,
 9427    ) -> Option<AnyElement> {
 9428        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9429            if menu.visible() {
 9430                menu.render_aside(max_size, window, cx)
 9431            } else {
 9432                None
 9433            }
 9434        })
 9435    }
 9436
 9437    fn hide_context_menu(
 9438        &mut self,
 9439        window: &mut Window,
 9440        cx: &mut Context<Self>,
 9441    ) -> Option<CodeContextMenu> {
 9442        cx.notify();
 9443        self.completion_tasks.clear();
 9444        let context_menu = self.context_menu.borrow_mut().take();
 9445        self.stale_inline_completion_in_menu.take();
 9446        self.update_visible_inline_completion(window, cx);
 9447        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9448            if let Some(completion_provider) = &self.completion_provider {
 9449                completion_provider.selection_changed(None, window, cx);
 9450            }
 9451        }
 9452        context_menu
 9453    }
 9454
 9455    fn show_snippet_choices(
 9456        &mut self,
 9457        choices: &Vec<String>,
 9458        selection: Range<Anchor>,
 9459        cx: &mut Context<Self>,
 9460    ) {
 9461        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9462            (Some(a), Some(b)) if a == b => a,
 9463            _ => {
 9464                log::error!("expected anchor range to have matching buffer IDs");
 9465                return;
 9466            }
 9467        };
 9468        let multi_buffer = self.buffer().read(cx);
 9469        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9470            return;
 9471        };
 9472
 9473        let id = post_inc(&mut self.next_completion_id);
 9474        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9475        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9476            CompletionsMenu::new_snippet_choices(
 9477                id,
 9478                true,
 9479                choices,
 9480                selection,
 9481                buffer,
 9482                snippet_sort_order,
 9483            ),
 9484        ));
 9485    }
 9486
 9487    pub fn insert_snippet(
 9488        &mut self,
 9489        insertion_ranges: &[Range<usize>],
 9490        snippet: Snippet,
 9491        window: &mut Window,
 9492        cx: &mut Context<Self>,
 9493    ) -> Result<()> {
 9494        struct Tabstop<T> {
 9495            is_end_tabstop: bool,
 9496            ranges: Vec<Range<T>>,
 9497            choices: Option<Vec<String>>,
 9498        }
 9499
 9500        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9501            let snippet_text: Arc<str> = snippet.text.clone().into();
 9502            let edits = insertion_ranges
 9503                .iter()
 9504                .cloned()
 9505                .map(|range| (range, snippet_text.clone()));
 9506            let autoindent_mode = AutoindentMode::Block {
 9507                original_indent_columns: Vec::new(),
 9508            };
 9509            buffer.edit(edits, Some(autoindent_mode), cx);
 9510
 9511            let snapshot = &*buffer.read(cx);
 9512            let snippet = &snippet;
 9513            snippet
 9514                .tabstops
 9515                .iter()
 9516                .map(|tabstop| {
 9517                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9518                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9519                    });
 9520                    let mut tabstop_ranges = tabstop
 9521                        .ranges
 9522                        .iter()
 9523                        .flat_map(|tabstop_range| {
 9524                            let mut delta = 0_isize;
 9525                            insertion_ranges.iter().map(move |insertion_range| {
 9526                                let insertion_start = insertion_range.start as isize + delta;
 9527                                delta +=
 9528                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9529
 9530                                let start = ((insertion_start + tabstop_range.start) as usize)
 9531                                    .min(snapshot.len());
 9532                                let end = ((insertion_start + tabstop_range.end) as usize)
 9533                                    .min(snapshot.len());
 9534                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9535                            })
 9536                        })
 9537                        .collect::<Vec<_>>();
 9538                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9539
 9540                    Tabstop {
 9541                        is_end_tabstop,
 9542                        ranges: tabstop_ranges,
 9543                        choices: tabstop.choices.clone(),
 9544                    }
 9545                })
 9546                .collect::<Vec<_>>()
 9547        });
 9548        if let Some(tabstop) = tabstops.first() {
 9549            self.change_selections(Default::default(), window, cx, |s| {
 9550                // Reverse order so that the first range is the newest created selection.
 9551                // Completions will use it and autoscroll will prioritize it.
 9552                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9553            });
 9554
 9555            if let Some(choices) = &tabstop.choices {
 9556                if let Some(selection) = tabstop.ranges.first() {
 9557                    self.show_snippet_choices(choices, selection.clone(), cx)
 9558                }
 9559            }
 9560
 9561            // If we're already at the last tabstop and it's at the end of the snippet,
 9562            // we're done, we don't need to keep the state around.
 9563            if !tabstop.is_end_tabstop {
 9564                let choices = tabstops
 9565                    .iter()
 9566                    .map(|tabstop| tabstop.choices.clone())
 9567                    .collect();
 9568
 9569                let ranges = tabstops
 9570                    .into_iter()
 9571                    .map(|tabstop| tabstop.ranges)
 9572                    .collect::<Vec<_>>();
 9573
 9574                self.snippet_stack.push(SnippetState {
 9575                    active_index: 0,
 9576                    ranges,
 9577                    choices,
 9578                });
 9579            }
 9580
 9581            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9582            if self.autoclose_regions.is_empty() {
 9583                let snapshot = self.buffer.read(cx).snapshot(cx);
 9584                let mut all_selections = self.selections.all::<Point>(cx);
 9585                for selection in &mut all_selections {
 9586                    let selection_head = selection.head();
 9587                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9588                        continue;
 9589                    };
 9590
 9591                    let mut bracket_pair = None;
 9592                    let max_lookup_length = scope
 9593                        .brackets()
 9594                        .map(|(pair, _)| {
 9595                            pair.start
 9596                                .as_str()
 9597                                .chars()
 9598                                .count()
 9599                                .max(pair.end.as_str().chars().count())
 9600                        })
 9601                        .max();
 9602                    if let Some(max_lookup_length) = max_lookup_length {
 9603                        let next_text = snapshot
 9604                            .chars_at(selection_head)
 9605                            .take(max_lookup_length)
 9606                            .collect::<String>();
 9607                        let prev_text = snapshot
 9608                            .reversed_chars_at(selection_head)
 9609                            .take(max_lookup_length)
 9610                            .collect::<String>();
 9611
 9612                        for (pair, enabled) in scope.brackets() {
 9613                            if enabled
 9614                                && pair.close
 9615                                && prev_text.starts_with(pair.start.as_str())
 9616                                && next_text.starts_with(pair.end.as_str())
 9617                            {
 9618                                bracket_pair = Some(pair.clone());
 9619                                break;
 9620                            }
 9621                        }
 9622                    }
 9623
 9624                    if let Some(pair) = bracket_pair {
 9625                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9626                        let autoclose_enabled =
 9627                            self.use_autoclose && snapshot_settings.use_autoclose;
 9628                        if autoclose_enabled {
 9629                            let start = snapshot.anchor_after(selection_head);
 9630                            let end = snapshot.anchor_after(selection_head);
 9631                            self.autoclose_regions.push(AutocloseRegion {
 9632                                selection_id: selection.id,
 9633                                range: start..end,
 9634                                pair,
 9635                            });
 9636                        }
 9637                    }
 9638                }
 9639            }
 9640        }
 9641        Ok(())
 9642    }
 9643
 9644    pub fn move_to_next_snippet_tabstop(
 9645        &mut self,
 9646        window: &mut Window,
 9647        cx: &mut Context<Self>,
 9648    ) -> bool {
 9649        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9650    }
 9651
 9652    pub fn move_to_prev_snippet_tabstop(
 9653        &mut self,
 9654        window: &mut Window,
 9655        cx: &mut Context<Self>,
 9656    ) -> bool {
 9657        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9658    }
 9659
 9660    pub fn move_to_snippet_tabstop(
 9661        &mut self,
 9662        bias: Bias,
 9663        window: &mut Window,
 9664        cx: &mut Context<Self>,
 9665    ) -> bool {
 9666        if let Some(mut snippet) = self.snippet_stack.pop() {
 9667            match bias {
 9668                Bias::Left => {
 9669                    if snippet.active_index > 0 {
 9670                        snippet.active_index -= 1;
 9671                    } else {
 9672                        self.snippet_stack.push(snippet);
 9673                        return false;
 9674                    }
 9675                }
 9676                Bias::Right => {
 9677                    if snippet.active_index + 1 < snippet.ranges.len() {
 9678                        snippet.active_index += 1;
 9679                    } else {
 9680                        self.snippet_stack.push(snippet);
 9681                        return false;
 9682                    }
 9683                }
 9684            }
 9685            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9686                self.change_selections(Default::default(), window, cx, |s| {
 9687                    // Reverse order so that the first range is the newest created selection.
 9688                    // Completions will use it and autoscroll will prioritize it.
 9689                    s.select_ranges(current_ranges.iter().rev().cloned())
 9690                });
 9691
 9692                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9693                    if let Some(selection) = current_ranges.first() {
 9694                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9695                    }
 9696                }
 9697
 9698                // If snippet state is not at the last tabstop, push it back on the stack
 9699                if snippet.active_index + 1 < snippet.ranges.len() {
 9700                    self.snippet_stack.push(snippet);
 9701                }
 9702                return true;
 9703            }
 9704        }
 9705
 9706        false
 9707    }
 9708
 9709    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9710        self.transact(window, cx, |this, window, cx| {
 9711            this.select_all(&SelectAll, window, cx);
 9712            this.insert("", window, cx);
 9713        });
 9714    }
 9715
 9716    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9717        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9718        self.transact(window, cx, |this, window, cx| {
 9719            this.select_autoclose_pair(window, cx);
 9720            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9721            if !this.linked_edit_ranges.is_empty() {
 9722                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9723                let snapshot = this.buffer.read(cx).snapshot(cx);
 9724
 9725                for selection in selections.iter() {
 9726                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9727                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9728                    if selection_start.buffer_id != selection_end.buffer_id {
 9729                        continue;
 9730                    }
 9731                    if let Some(ranges) =
 9732                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9733                    {
 9734                        for (buffer, entries) in ranges {
 9735                            linked_ranges.entry(buffer).or_default().extend(entries);
 9736                        }
 9737                    }
 9738                }
 9739            }
 9740
 9741            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9742            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9743            for selection in &mut selections {
 9744                if selection.is_empty() {
 9745                    let old_head = selection.head();
 9746                    let mut new_head =
 9747                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9748                            .to_point(&display_map);
 9749                    if let Some((buffer, line_buffer_range)) = display_map
 9750                        .buffer_snapshot
 9751                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9752                    {
 9753                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9754                        let indent_len = match indent_size.kind {
 9755                            IndentKind::Space => {
 9756                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9757                            }
 9758                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9759                        };
 9760                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9761                            let indent_len = indent_len.get();
 9762                            new_head = cmp::min(
 9763                                new_head,
 9764                                MultiBufferPoint::new(
 9765                                    old_head.row,
 9766                                    ((old_head.column - 1) / indent_len) * indent_len,
 9767                                ),
 9768                            );
 9769                        }
 9770                    }
 9771
 9772                    selection.set_head(new_head, SelectionGoal::None);
 9773                }
 9774            }
 9775
 9776            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9777            this.insert("", window, cx);
 9778            let empty_str: Arc<str> = Arc::from("");
 9779            for (buffer, edits) in linked_ranges {
 9780                let snapshot = buffer.read(cx).snapshot();
 9781                use text::ToPoint as TP;
 9782
 9783                let edits = edits
 9784                    .into_iter()
 9785                    .map(|range| {
 9786                        let end_point = TP::to_point(&range.end, &snapshot);
 9787                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9788
 9789                        if end_point == start_point {
 9790                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9791                                .saturating_sub(1);
 9792                            start_point =
 9793                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9794                        };
 9795
 9796                        (start_point..end_point, empty_str.clone())
 9797                    })
 9798                    .sorted_by_key(|(range, _)| range.start)
 9799                    .collect::<Vec<_>>();
 9800                buffer.update(cx, |this, cx| {
 9801                    this.edit(edits, None, cx);
 9802                })
 9803            }
 9804            this.refresh_inline_completion(true, false, window, cx);
 9805            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9806        });
 9807    }
 9808
 9809    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9810        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9811        self.transact(window, cx, |this, window, cx| {
 9812            this.change_selections(Default::default(), window, cx, |s| {
 9813                s.move_with(|map, selection| {
 9814                    if selection.is_empty() {
 9815                        let cursor = movement::right(map, selection.head());
 9816                        selection.end = cursor;
 9817                        selection.reversed = true;
 9818                        selection.goal = SelectionGoal::None;
 9819                    }
 9820                })
 9821            });
 9822            this.insert("", window, cx);
 9823            this.refresh_inline_completion(true, false, window, cx);
 9824        });
 9825    }
 9826
 9827    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9828        if self.mode.is_single_line() {
 9829            cx.propagate();
 9830            return;
 9831        }
 9832
 9833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9834        if self.move_to_prev_snippet_tabstop(window, cx) {
 9835            return;
 9836        }
 9837        self.outdent(&Outdent, window, cx);
 9838    }
 9839
 9840    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9841        if self.mode.is_single_line() {
 9842            cx.propagate();
 9843            return;
 9844        }
 9845
 9846        if self.move_to_next_snippet_tabstop(window, cx) {
 9847            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848            return;
 9849        }
 9850        if self.read_only(cx) {
 9851            return;
 9852        }
 9853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9854        let mut selections = self.selections.all_adjusted(cx);
 9855        let buffer = self.buffer.read(cx);
 9856        let snapshot = buffer.snapshot(cx);
 9857        let rows_iter = selections.iter().map(|s| s.head().row);
 9858        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9859
 9860        let has_some_cursor_in_whitespace = selections
 9861            .iter()
 9862            .filter(|selection| selection.is_empty())
 9863            .any(|selection| {
 9864                let cursor = selection.head();
 9865                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9866                cursor.column < current_indent.len
 9867            });
 9868
 9869        let mut edits = Vec::new();
 9870        let mut prev_edited_row = 0;
 9871        let mut row_delta = 0;
 9872        for selection in &mut selections {
 9873            if selection.start.row != prev_edited_row {
 9874                row_delta = 0;
 9875            }
 9876            prev_edited_row = selection.end.row;
 9877
 9878            // If the selection is non-empty, then increase the indentation of the selected lines.
 9879            if !selection.is_empty() {
 9880                row_delta =
 9881                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9882                continue;
 9883            }
 9884
 9885            let cursor = selection.head();
 9886            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9887            if let Some(suggested_indent) =
 9888                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9889            {
 9890                // Don't do anything if already at suggested indent
 9891                // and there is any other cursor which is not
 9892                if has_some_cursor_in_whitespace
 9893                    && cursor.column == current_indent.len
 9894                    && current_indent.len == suggested_indent.len
 9895                {
 9896                    continue;
 9897                }
 9898
 9899                // Adjust line and move cursor to suggested indent
 9900                // if cursor is not at suggested indent
 9901                if cursor.column < suggested_indent.len
 9902                    && cursor.column <= current_indent.len
 9903                    && current_indent.len <= suggested_indent.len
 9904                {
 9905                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9906                    selection.end = selection.start;
 9907                    if row_delta == 0 {
 9908                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9909                            cursor.row,
 9910                            current_indent,
 9911                            suggested_indent,
 9912                        ));
 9913                        row_delta = suggested_indent.len - current_indent.len;
 9914                    }
 9915                    continue;
 9916                }
 9917
 9918                // If current indent is more than suggested indent
 9919                // only move cursor to current indent and skip indent
 9920                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9921                    selection.start = Point::new(cursor.row, current_indent.len);
 9922                    selection.end = selection.start;
 9923                    continue;
 9924                }
 9925            }
 9926
 9927            // Otherwise, insert a hard or soft tab.
 9928            let settings = buffer.language_settings_at(cursor, cx);
 9929            let tab_size = if settings.hard_tabs {
 9930                IndentSize::tab()
 9931            } else {
 9932                let tab_size = settings.tab_size.get();
 9933                let indent_remainder = snapshot
 9934                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9935                    .flat_map(str::chars)
 9936                    .fold(row_delta % tab_size, |counter: u32, c| {
 9937                        if c == '\t' {
 9938                            0
 9939                        } else {
 9940                            (counter + 1) % tab_size
 9941                        }
 9942                    });
 9943
 9944                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9945                IndentSize::spaces(chars_to_next_tab_stop)
 9946            };
 9947            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9948            selection.end = selection.start;
 9949            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9950            row_delta += tab_size.len;
 9951        }
 9952
 9953        self.transact(window, cx, |this, window, cx| {
 9954            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9955            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9956            this.refresh_inline_completion(true, false, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.read_only(cx) {
 9962            return;
 9963        }
 9964        if self.mode.is_single_line() {
 9965            cx.propagate();
 9966            return;
 9967        }
 9968
 9969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9970        let mut selections = self.selections.all::<Point>(cx);
 9971        let mut prev_edited_row = 0;
 9972        let mut row_delta = 0;
 9973        let mut edits = Vec::new();
 9974        let buffer = self.buffer.read(cx);
 9975        let snapshot = buffer.snapshot(cx);
 9976        for selection in &mut selections {
 9977            if selection.start.row != prev_edited_row {
 9978                row_delta = 0;
 9979            }
 9980            prev_edited_row = selection.end.row;
 9981
 9982            row_delta =
 9983                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9984        }
 9985
 9986        self.transact(window, cx, |this, window, cx| {
 9987            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9988            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9989        });
 9990    }
 9991
 9992    fn indent_selection(
 9993        buffer: &MultiBuffer,
 9994        snapshot: &MultiBufferSnapshot,
 9995        selection: &mut Selection<Point>,
 9996        edits: &mut Vec<(Range<Point>, String)>,
 9997        delta_for_start_row: u32,
 9998        cx: &App,
 9999    ) -> u32 {
10000        let settings = buffer.language_settings_at(selection.start, cx);
10001        let tab_size = settings.tab_size.get();
10002        let indent_kind = if settings.hard_tabs {
10003            IndentKind::Tab
10004        } else {
10005            IndentKind::Space
10006        };
10007        let mut start_row = selection.start.row;
10008        let mut end_row = selection.end.row + 1;
10009
10010        // If a selection ends at the beginning of a line, don't indent
10011        // that last line.
10012        if selection.end.column == 0 && selection.end.row > selection.start.row {
10013            end_row -= 1;
10014        }
10015
10016        // Avoid re-indenting a row that has already been indented by a
10017        // previous selection, but still update this selection's column
10018        // to reflect that indentation.
10019        if delta_for_start_row > 0 {
10020            start_row += 1;
10021            selection.start.column += delta_for_start_row;
10022            if selection.end.row == selection.start.row {
10023                selection.end.column += delta_for_start_row;
10024            }
10025        }
10026
10027        let mut delta_for_end_row = 0;
10028        let has_multiple_rows = start_row + 1 != end_row;
10029        for row in start_row..end_row {
10030            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10031            let indent_delta = match (current_indent.kind, indent_kind) {
10032                (IndentKind::Space, IndentKind::Space) => {
10033                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10034                    IndentSize::spaces(columns_to_next_tab_stop)
10035                }
10036                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10037                (_, IndentKind::Tab) => IndentSize::tab(),
10038            };
10039
10040            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10041                0
10042            } else {
10043                selection.start.column
10044            };
10045            let row_start = Point::new(row, start);
10046            edits.push((
10047                row_start..row_start,
10048                indent_delta.chars().collect::<String>(),
10049            ));
10050
10051            // Update this selection's endpoints to reflect the indentation.
10052            if row == selection.start.row {
10053                selection.start.column += indent_delta.len;
10054            }
10055            if row == selection.end.row {
10056                selection.end.column += indent_delta.len;
10057                delta_for_end_row = indent_delta.len;
10058            }
10059        }
10060
10061        if selection.start.row == selection.end.row {
10062            delta_for_start_row + delta_for_end_row
10063        } else {
10064            delta_for_end_row
10065        }
10066    }
10067
10068    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10069        if self.read_only(cx) {
10070            return;
10071        }
10072        if self.mode.is_single_line() {
10073            cx.propagate();
10074            return;
10075        }
10076
10077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10079        let selections = self.selections.all::<Point>(cx);
10080        let mut deletion_ranges = Vec::new();
10081        let mut last_outdent = None;
10082        {
10083            let buffer = self.buffer.read(cx);
10084            let snapshot = buffer.snapshot(cx);
10085            for selection in &selections {
10086                let settings = buffer.language_settings_at(selection.start, cx);
10087                let tab_size = settings.tab_size.get();
10088                let mut rows = selection.spanned_rows(false, &display_map);
10089
10090                // Avoid re-outdenting a row that has already been outdented by a
10091                // previous selection.
10092                if let Some(last_row) = last_outdent {
10093                    if last_row == rows.start {
10094                        rows.start = rows.start.next_row();
10095                    }
10096                }
10097                let has_multiple_rows = rows.len() > 1;
10098                for row in rows.iter_rows() {
10099                    let indent_size = snapshot.indent_size_for_line(row);
10100                    if indent_size.len > 0 {
10101                        let deletion_len = match indent_size.kind {
10102                            IndentKind::Space => {
10103                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10104                                if columns_to_prev_tab_stop == 0 {
10105                                    tab_size
10106                                } else {
10107                                    columns_to_prev_tab_stop
10108                                }
10109                            }
10110                            IndentKind::Tab => 1,
10111                        };
10112                        let start = if has_multiple_rows
10113                            || deletion_len > selection.start.column
10114                            || indent_size.len < selection.start.column
10115                        {
10116                            0
10117                        } else {
10118                            selection.start.column - deletion_len
10119                        };
10120                        deletion_ranges.push(
10121                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10122                        );
10123                        last_outdent = Some(row);
10124                    }
10125                }
10126            }
10127        }
10128
10129        self.transact(window, cx, |this, window, cx| {
10130            this.buffer.update(cx, |buffer, cx| {
10131                let empty_str: Arc<str> = Arc::default();
10132                buffer.edit(
10133                    deletion_ranges
10134                        .into_iter()
10135                        .map(|range| (range, empty_str.clone())),
10136                    None,
10137                    cx,
10138                );
10139            });
10140            let selections = this.selections.all::<usize>(cx);
10141            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10142        });
10143    }
10144
10145    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10146        if self.read_only(cx) {
10147            return;
10148        }
10149        if self.mode.is_single_line() {
10150            cx.propagate();
10151            return;
10152        }
10153
10154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10155        let selections = self
10156            .selections
10157            .all::<usize>(cx)
10158            .into_iter()
10159            .map(|s| s.range());
10160
10161        self.transact(window, cx, |this, window, cx| {
10162            this.buffer.update(cx, |buffer, cx| {
10163                buffer.autoindent_ranges(selections, cx);
10164            });
10165            let selections = this.selections.all::<usize>(cx);
10166            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10167        });
10168    }
10169
10170    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10173        let selections = self.selections.all::<Point>(cx);
10174
10175        let mut new_cursors = Vec::new();
10176        let mut edit_ranges = Vec::new();
10177        let mut selections = selections.iter().peekable();
10178        while let Some(selection) = selections.next() {
10179            let mut rows = selection.spanned_rows(false, &display_map);
10180            let goal_display_column = selection.head().to_display_point(&display_map).column();
10181
10182            // Accumulate contiguous regions of rows that we want to delete.
10183            while let Some(next_selection) = selections.peek() {
10184                let next_rows = next_selection.spanned_rows(false, &display_map);
10185                if next_rows.start <= rows.end {
10186                    rows.end = next_rows.end;
10187                    selections.next().unwrap();
10188                } else {
10189                    break;
10190                }
10191            }
10192
10193            let buffer = &display_map.buffer_snapshot;
10194            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10195            let edit_end;
10196            let cursor_buffer_row;
10197            if buffer.max_point().row >= rows.end.0 {
10198                // If there's a line after the range, delete the \n from the end of the row range
10199                // and position the cursor on the next line.
10200                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10201                cursor_buffer_row = rows.end;
10202            } else {
10203                // If there isn't a line after the range, delete the \n from the line before the
10204                // start of the row range and position the cursor there.
10205                edit_start = edit_start.saturating_sub(1);
10206                edit_end = buffer.len();
10207                cursor_buffer_row = rows.start.previous_row();
10208            }
10209
10210            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10211            *cursor.column_mut() =
10212                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10213
10214            new_cursors.push((
10215                selection.id,
10216                buffer.anchor_after(cursor.to_point(&display_map)),
10217            ));
10218            edit_ranges.push(edit_start..edit_end);
10219        }
10220
10221        self.transact(window, cx, |this, window, cx| {
10222            let buffer = this.buffer.update(cx, |buffer, cx| {
10223                let empty_str: Arc<str> = Arc::default();
10224                buffer.edit(
10225                    edit_ranges
10226                        .into_iter()
10227                        .map(|range| (range, empty_str.clone())),
10228                    None,
10229                    cx,
10230                );
10231                buffer.snapshot(cx)
10232            });
10233            let new_selections = new_cursors
10234                .into_iter()
10235                .map(|(id, cursor)| {
10236                    let cursor = cursor.to_point(&buffer);
10237                    Selection {
10238                        id,
10239                        start: cursor,
10240                        end: cursor,
10241                        reversed: false,
10242                        goal: SelectionGoal::None,
10243                    }
10244                })
10245                .collect();
10246
10247            this.change_selections(Default::default(), window, cx, |s| {
10248                s.select(new_selections);
10249            });
10250        });
10251    }
10252
10253    pub fn join_lines_impl(
10254        &mut self,
10255        insert_whitespace: bool,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10263        for selection in self.selections.all::<Point>(cx) {
10264            let start = MultiBufferRow(selection.start.row);
10265            // Treat single line selections as if they include the next line. Otherwise this action
10266            // would do nothing for single line selections individual cursors.
10267            let end = if selection.start.row == selection.end.row {
10268                MultiBufferRow(selection.start.row + 1)
10269            } else {
10270                MultiBufferRow(selection.end.row)
10271            };
10272
10273            if let Some(last_row_range) = row_ranges.last_mut() {
10274                if start <= last_row_range.end {
10275                    last_row_range.end = end;
10276                    continue;
10277                }
10278            }
10279            row_ranges.push(start..end);
10280        }
10281
10282        let snapshot = self.buffer.read(cx).snapshot(cx);
10283        let mut cursor_positions = Vec::new();
10284        for row_range in &row_ranges {
10285            let anchor = snapshot.anchor_before(Point::new(
10286                row_range.end.previous_row().0,
10287                snapshot.line_len(row_range.end.previous_row()),
10288            ));
10289            cursor_positions.push(anchor..anchor);
10290        }
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            for row_range in row_ranges.into_iter().rev() {
10294                for row in row_range.iter_rows().rev() {
10295                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10296                    let next_line_row = row.next_row();
10297                    let indent = snapshot.indent_size_for_line(next_line_row);
10298                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10299
10300                    let replace =
10301                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10302                            " "
10303                        } else {
10304                            ""
10305                        };
10306
10307                    this.buffer.update(cx, |buffer, cx| {
10308                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10309                    });
10310                }
10311            }
10312
10313            this.change_selections(Default::default(), window, cx, |s| {
10314                s.select_anchor_ranges(cursor_positions)
10315            });
10316        });
10317    }
10318
10319    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10321        self.join_lines_impl(true, window, cx);
10322    }
10323
10324    pub fn sort_lines_case_sensitive(
10325        &mut self,
10326        _: &SortLinesCaseSensitive,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10331    }
10332
10333    pub fn sort_lines_by_length(
10334        &mut self,
10335        _: &SortLinesByLength,
10336        window: &mut Window,
10337        cx: &mut Context<Self>,
10338    ) {
10339        self.manipulate_immutable_lines(window, cx, |lines| {
10340            lines.sort_by_key(|&line| line.chars().count())
10341        })
10342    }
10343
10344    pub fn sort_lines_case_insensitive(
10345        &mut self,
10346        _: &SortLinesCaseInsensitive,
10347        window: &mut Window,
10348        cx: &mut Context<Self>,
10349    ) {
10350        self.manipulate_immutable_lines(window, cx, |lines| {
10351            lines.sort_by_key(|line| line.to_lowercase())
10352        })
10353    }
10354
10355    pub fn unique_lines_case_insensitive(
10356        &mut self,
10357        _: &UniqueLinesCaseInsensitive,
10358        window: &mut Window,
10359        cx: &mut Context<Self>,
10360    ) {
10361        self.manipulate_immutable_lines(window, cx, |lines| {
10362            let mut seen = HashSet::default();
10363            lines.retain(|line| seen.insert(line.to_lowercase()));
10364        })
10365    }
10366
10367    pub fn unique_lines_case_sensitive(
10368        &mut self,
10369        _: &UniqueLinesCaseSensitive,
10370        window: &mut Window,
10371        cx: &mut Context<Self>,
10372    ) {
10373        self.manipulate_immutable_lines(window, cx, |lines| {
10374            let mut seen = HashSet::default();
10375            lines.retain(|line| seen.insert(*line));
10376        })
10377    }
10378
10379    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10380        let Some(project) = self.project.clone() else {
10381            return;
10382        };
10383        self.reload(project, window, cx)
10384            .detach_and_notify_err(window, cx);
10385    }
10386
10387    pub fn restore_file(
10388        &mut self,
10389        _: &::git::RestoreFile,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10394        let mut buffer_ids = HashSet::default();
10395        let snapshot = self.buffer().read(cx).snapshot(cx);
10396        for selection in self.selections.all::<usize>(cx) {
10397            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10398        }
10399
10400        let buffer = self.buffer().read(cx);
10401        let ranges = buffer_ids
10402            .into_iter()
10403            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10404            .collect::<Vec<_>>();
10405
10406        self.restore_hunks_in_ranges(ranges, window, cx);
10407    }
10408
10409    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10411        let selections = self
10412            .selections
10413            .all(cx)
10414            .into_iter()
10415            .map(|s| s.range())
10416            .collect();
10417        self.restore_hunks_in_ranges(selections, window, cx);
10418    }
10419
10420    pub fn restore_hunks_in_ranges(
10421        &mut self,
10422        ranges: Vec<Range<Point>>,
10423        window: &mut Window,
10424        cx: &mut Context<Editor>,
10425    ) {
10426        let mut revert_changes = HashMap::default();
10427        let chunk_by = self
10428            .snapshot(window, cx)
10429            .hunks_for_ranges(ranges)
10430            .into_iter()
10431            .chunk_by(|hunk| hunk.buffer_id);
10432        for (buffer_id, hunks) in &chunk_by {
10433            let hunks = hunks.collect::<Vec<_>>();
10434            for hunk in &hunks {
10435                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10436            }
10437            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10438        }
10439        drop(chunk_by);
10440        if !revert_changes.is_empty() {
10441            self.transact(window, cx, |editor, window, cx| {
10442                editor.restore(revert_changes, window, cx);
10443            });
10444        }
10445    }
10446
10447    pub fn open_active_item_in_terminal(
10448        &mut self,
10449        _: &OpenInTerminal,
10450        window: &mut Window,
10451        cx: &mut Context<Self>,
10452    ) {
10453        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10454            let project_path = buffer.read(cx).project_path(cx)?;
10455            let project = self.project.as_ref()?.read(cx);
10456            let entry = project.entry_for_path(&project_path, cx)?;
10457            let parent = match &entry.canonical_path {
10458                Some(canonical_path) => canonical_path.to_path_buf(),
10459                None => project.absolute_path(&project_path, cx)?,
10460            }
10461            .parent()?
10462            .to_path_buf();
10463            Some(parent)
10464        }) {
10465            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10466        }
10467    }
10468
10469    fn set_breakpoint_context_menu(
10470        &mut self,
10471        display_row: DisplayRow,
10472        position: Option<Anchor>,
10473        clicked_point: gpui::Point<Pixels>,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        let source = self
10478            .buffer
10479            .read(cx)
10480            .snapshot(cx)
10481            .anchor_before(Point::new(display_row.0, 0u32));
10482
10483        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10484
10485        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10486            self,
10487            source,
10488            clicked_point,
10489            context_menu,
10490            window,
10491            cx,
10492        );
10493    }
10494
10495    fn add_edit_breakpoint_block(
10496        &mut self,
10497        anchor: Anchor,
10498        breakpoint: &Breakpoint,
10499        edit_action: BreakpointPromptEditAction,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        let weak_editor = cx.weak_entity();
10504        let bp_prompt = cx.new(|cx| {
10505            BreakpointPromptEditor::new(
10506                weak_editor,
10507                anchor,
10508                breakpoint.clone(),
10509                edit_action,
10510                window,
10511                cx,
10512            )
10513        });
10514
10515        let height = bp_prompt.update(cx, |this, cx| {
10516            this.prompt
10517                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10518        });
10519        let cloned_prompt = bp_prompt.clone();
10520        let blocks = vec![BlockProperties {
10521            style: BlockStyle::Sticky,
10522            placement: BlockPlacement::Above(anchor),
10523            height: Some(height),
10524            render: Arc::new(move |cx| {
10525                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10526                cloned_prompt.clone().into_any_element()
10527            }),
10528            priority: 0,
10529        }];
10530
10531        let focus_handle = bp_prompt.focus_handle(cx);
10532        window.focus(&focus_handle);
10533
10534        let block_ids = self.insert_blocks(blocks, None, cx);
10535        bp_prompt.update(cx, |prompt, _| {
10536            prompt.add_block_ids(block_ids);
10537        });
10538    }
10539
10540    pub(crate) fn breakpoint_at_row(
10541        &self,
10542        row: u32,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) -> Option<(Anchor, Breakpoint)> {
10546        let snapshot = self.snapshot(window, cx);
10547        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10548
10549        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10550    }
10551
10552    pub(crate) fn breakpoint_at_anchor(
10553        &self,
10554        breakpoint_position: Anchor,
10555        snapshot: &EditorSnapshot,
10556        cx: &mut Context<Self>,
10557    ) -> Option<(Anchor, Breakpoint)> {
10558        let project = self.project.clone()?;
10559
10560        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10561            snapshot
10562                .buffer_snapshot
10563                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10564        })?;
10565
10566        let enclosing_excerpt = breakpoint_position.excerpt_id;
10567        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10568        let buffer_snapshot = buffer.read(cx).snapshot();
10569
10570        let row = buffer_snapshot
10571            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10572            .row;
10573
10574        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10575        let anchor_end = snapshot
10576            .buffer_snapshot
10577            .anchor_after(Point::new(row, line_len));
10578
10579        let bp = self
10580            .breakpoint_store
10581            .as_ref()?
10582            .read_with(cx, |breakpoint_store, cx| {
10583                breakpoint_store
10584                    .breakpoints(
10585                        &buffer,
10586                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10587                        &buffer_snapshot,
10588                        cx,
10589                    )
10590                    .next()
10591                    .and_then(|(bp, _)| {
10592                        let breakpoint_row = buffer_snapshot
10593                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10594                            .row;
10595
10596                        if breakpoint_row == row {
10597                            snapshot
10598                                .buffer_snapshot
10599                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10600                                .map(|position| (position, bp.bp.clone()))
10601                        } else {
10602                            None
10603                        }
10604                    })
10605            });
10606        bp
10607    }
10608
10609    pub fn edit_log_breakpoint(
10610        &mut self,
10611        _: &EditLogBreakpoint,
10612        window: &mut Window,
10613        cx: &mut Context<Self>,
10614    ) {
10615        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10616            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10617                message: None,
10618                state: BreakpointState::Enabled,
10619                condition: None,
10620                hit_condition: None,
10621            });
10622
10623            self.add_edit_breakpoint_block(
10624                anchor,
10625                &breakpoint,
10626                BreakpointPromptEditAction::Log,
10627                window,
10628                cx,
10629            );
10630        }
10631    }
10632
10633    fn breakpoints_at_cursors(
10634        &self,
10635        window: &mut Window,
10636        cx: &mut Context<Self>,
10637    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10638        let snapshot = self.snapshot(window, cx);
10639        let cursors = self
10640            .selections
10641            .disjoint_anchors()
10642            .into_iter()
10643            .map(|selection| {
10644                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10645
10646                let breakpoint_position = self
10647                    .breakpoint_at_row(cursor_position.row, window, cx)
10648                    .map(|bp| bp.0)
10649                    .unwrap_or_else(|| {
10650                        snapshot
10651                            .display_snapshot
10652                            .buffer_snapshot
10653                            .anchor_after(Point::new(cursor_position.row, 0))
10654                    });
10655
10656                let breakpoint = self
10657                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10658                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10659
10660                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10661            })
10662            // 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.
10663            .collect::<HashMap<Anchor, _>>();
10664
10665        cursors.into_iter().collect()
10666    }
10667
10668    pub fn enable_breakpoint(
10669        &mut self,
10670        _: &crate::actions::EnableBreakpoint,
10671        window: &mut Window,
10672        cx: &mut Context<Self>,
10673    ) {
10674        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10675            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10676                continue;
10677            };
10678            self.edit_breakpoint_at_anchor(
10679                anchor,
10680                breakpoint,
10681                BreakpointEditAction::InvertState,
10682                cx,
10683            );
10684        }
10685    }
10686
10687    pub fn disable_breakpoint(
10688        &mut self,
10689        _: &crate::actions::DisableBreakpoint,
10690        window: &mut Window,
10691        cx: &mut Context<Self>,
10692    ) {
10693        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10694            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10695                continue;
10696            };
10697            self.edit_breakpoint_at_anchor(
10698                anchor,
10699                breakpoint,
10700                BreakpointEditAction::InvertState,
10701                cx,
10702            );
10703        }
10704    }
10705
10706    pub fn toggle_breakpoint(
10707        &mut self,
10708        _: &crate::actions::ToggleBreakpoint,
10709        window: &mut Window,
10710        cx: &mut Context<Self>,
10711    ) {
10712        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10713            if let Some(breakpoint) = breakpoint {
10714                self.edit_breakpoint_at_anchor(
10715                    anchor,
10716                    breakpoint,
10717                    BreakpointEditAction::Toggle,
10718                    cx,
10719                );
10720            } else {
10721                self.edit_breakpoint_at_anchor(
10722                    anchor,
10723                    Breakpoint::new_standard(),
10724                    BreakpointEditAction::Toggle,
10725                    cx,
10726                );
10727            }
10728        }
10729    }
10730
10731    pub fn edit_breakpoint_at_anchor(
10732        &mut self,
10733        breakpoint_position: Anchor,
10734        breakpoint: Breakpoint,
10735        edit_action: BreakpointEditAction,
10736        cx: &mut Context<Self>,
10737    ) {
10738        let Some(breakpoint_store) = &self.breakpoint_store else {
10739            return;
10740        };
10741
10742        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10743            if breakpoint_position == Anchor::min() {
10744                self.buffer()
10745                    .read(cx)
10746                    .excerpt_buffer_ids()
10747                    .into_iter()
10748                    .next()
10749            } else {
10750                None
10751            }
10752        }) else {
10753            return;
10754        };
10755
10756        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10757            return;
10758        };
10759
10760        breakpoint_store.update(cx, |breakpoint_store, cx| {
10761            breakpoint_store.toggle_breakpoint(
10762                buffer,
10763                BreakpointWithPosition {
10764                    position: breakpoint_position.text_anchor,
10765                    bp: breakpoint,
10766                },
10767                edit_action,
10768                cx,
10769            );
10770        });
10771
10772        cx.notify();
10773    }
10774
10775    #[cfg(any(test, feature = "test-support"))]
10776    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10777        self.breakpoint_store.clone()
10778    }
10779
10780    pub fn prepare_restore_change(
10781        &self,
10782        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10783        hunk: &MultiBufferDiffHunk,
10784        cx: &mut App,
10785    ) -> Option<()> {
10786        if hunk.is_created_file() {
10787            return None;
10788        }
10789        let buffer = self.buffer.read(cx);
10790        let diff = buffer.diff_for(hunk.buffer_id)?;
10791        let buffer = buffer.buffer(hunk.buffer_id)?;
10792        let buffer = buffer.read(cx);
10793        let original_text = diff
10794            .read(cx)
10795            .base_text()
10796            .as_rope()
10797            .slice(hunk.diff_base_byte_range.clone());
10798        let buffer_snapshot = buffer.snapshot();
10799        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10800        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10801            probe
10802                .0
10803                .start
10804                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10805                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10806        }) {
10807            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10808            Some(())
10809        } else {
10810            None
10811        }
10812    }
10813
10814    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10815        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10816    }
10817
10818    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10819        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10820    }
10821
10822    fn manipulate_lines<M>(
10823        &mut self,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826        mut manipulate: M,
10827    ) where
10828        M: FnMut(&str) -> LineManipulationResult,
10829    {
10830        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10831
10832        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10833        let buffer = self.buffer.read(cx).snapshot(cx);
10834
10835        let mut edits = Vec::new();
10836
10837        let selections = self.selections.all::<Point>(cx);
10838        let mut selections = selections.iter().peekable();
10839        let mut contiguous_row_selections = Vec::new();
10840        let mut new_selections = Vec::new();
10841        let mut added_lines = 0;
10842        let mut removed_lines = 0;
10843
10844        while let Some(selection) = selections.next() {
10845            let (start_row, end_row) = consume_contiguous_rows(
10846                &mut contiguous_row_selections,
10847                selection,
10848                &display_map,
10849                &mut selections,
10850            );
10851
10852            let start_point = Point::new(start_row.0, 0);
10853            let end_point = Point::new(
10854                end_row.previous_row().0,
10855                buffer.line_len(end_row.previous_row()),
10856            );
10857            let text = buffer
10858                .text_for_range(start_point..end_point)
10859                .collect::<String>();
10860
10861            let LineManipulationResult {
10862                new_text,
10863                line_count_before,
10864                line_count_after,
10865            } = manipulate(&text);
10866
10867            edits.push((start_point..end_point, new_text));
10868
10869            // Selections must change based on added and removed line count
10870            let start_row =
10871                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10872            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10873            new_selections.push(Selection {
10874                id: selection.id,
10875                start: start_row,
10876                end: end_row,
10877                goal: SelectionGoal::None,
10878                reversed: selection.reversed,
10879            });
10880
10881            if line_count_after > line_count_before {
10882                added_lines += line_count_after - line_count_before;
10883            } else if line_count_before > line_count_after {
10884                removed_lines += line_count_before - line_count_after;
10885            }
10886        }
10887
10888        self.transact(window, cx, |this, window, cx| {
10889            let buffer = this.buffer.update(cx, |buffer, cx| {
10890                buffer.edit(edits, None, cx);
10891                buffer.snapshot(cx)
10892            });
10893
10894            // Recalculate offsets on newly edited buffer
10895            let new_selections = new_selections
10896                .iter()
10897                .map(|s| {
10898                    let start_point = Point::new(s.start.0, 0);
10899                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10900                    Selection {
10901                        id: s.id,
10902                        start: buffer.point_to_offset(start_point),
10903                        end: buffer.point_to_offset(end_point),
10904                        goal: s.goal,
10905                        reversed: s.reversed,
10906                    }
10907                })
10908                .collect();
10909
10910            this.change_selections(Default::default(), window, cx, |s| {
10911                s.select(new_selections);
10912            });
10913
10914            this.request_autoscroll(Autoscroll::fit(), cx);
10915        });
10916    }
10917
10918    fn manipulate_immutable_lines<Fn>(
10919        &mut self,
10920        window: &mut Window,
10921        cx: &mut Context<Self>,
10922        mut callback: Fn,
10923    ) where
10924        Fn: FnMut(&mut Vec<&str>),
10925    {
10926        self.manipulate_lines(window, cx, |text| {
10927            let mut lines: Vec<&str> = text.split('\n').collect();
10928            let line_count_before = lines.len();
10929
10930            callback(&mut lines);
10931
10932            LineManipulationResult {
10933                new_text: lines.join("\n"),
10934                line_count_before,
10935                line_count_after: lines.len(),
10936            }
10937        });
10938    }
10939
10940    fn manipulate_mutable_lines<Fn>(
10941        &mut self,
10942        window: &mut Window,
10943        cx: &mut Context<Self>,
10944        mut callback: Fn,
10945    ) where
10946        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10947    {
10948        self.manipulate_lines(window, cx, |text| {
10949            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10950            let line_count_before = lines.len();
10951
10952            callback(&mut lines);
10953
10954            LineManipulationResult {
10955                new_text: lines.join("\n"),
10956                line_count_before,
10957                line_count_after: lines.len(),
10958            }
10959        });
10960    }
10961
10962    pub fn convert_indentation_to_spaces(
10963        &mut self,
10964        _: &ConvertIndentationToSpaces,
10965        window: &mut Window,
10966        cx: &mut Context<Self>,
10967    ) {
10968        let settings = self.buffer.read(cx).language_settings(cx);
10969        let tab_size = settings.tab_size.get() as usize;
10970
10971        self.manipulate_mutable_lines(window, cx, |lines| {
10972            // Allocates a reasonably sized scratch buffer once for the whole loop
10973            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10974            // Avoids recomputing spaces that could be inserted many times
10975            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10976                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10977                .collect();
10978
10979            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10980                let mut chars = line.as_ref().chars();
10981                let mut col = 0;
10982                let mut changed = false;
10983
10984                while let Some(ch) = chars.next() {
10985                    match ch {
10986                        ' ' => {
10987                            reindented_line.push(' ');
10988                            col += 1;
10989                        }
10990                        '\t' => {
10991                            // \t are converted to spaces depending on the current column
10992                            let spaces_len = tab_size - (col % tab_size);
10993                            reindented_line.extend(&space_cache[spaces_len - 1]);
10994                            col += spaces_len;
10995                            changed = true;
10996                        }
10997                        _ => {
10998                            // If we dont append before break, the character is consumed
10999                            reindented_line.push(ch);
11000                            break;
11001                        }
11002                    }
11003                }
11004
11005                if !changed {
11006                    reindented_line.clear();
11007                    continue;
11008                }
11009                // Append the rest of the line and replace old reference with new one
11010                reindented_line.extend(chars);
11011                *line = Cow::Owned(reindented_line.clone());
11012                reindented_line.clear();
11013            }
11014        });
11015    }
11016
11017    pub fn convert_indentation_to_tabs(
11018        &mut self,
11019        _: &ConvertIndentationToTabs,
11020        window: &mut Window,
11021        cx: &mut Context<Self>,
11022    ) {
11023        let settings = self.buffer.read(cx).language_settings(cx);
11024        let tab_size = settings.tab_size.get() as usize;
11025
11026        self.manipulate_mutable_lines(window, cx, |lines| {
11027            // Allocates a reasonably sized buffer once for the whole loop
11028            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11029            // Avoids recomputing spaces that could be inserted many times
11030            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11031                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11032                .collect();
11033
11034            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11035                let mut chars = line.chars();
11036                let mut spaces_count = 0;
11037                let mut first_non_indent_char = None;
11038                let mut changed = false;
11039
11040                while let Some(ch) = chars.next() {
11041                    match ch {
11042                        ' ' => {
11043                            // Keep track of spaces. Append \t when we reach tab_size
11044                            spaces_count += 1;
11045                            changed = true;
11046                            if spaces_count == tab_size {
11047                                reindented_line.push('\t');
11048                                spaces_count = 0;
11049                            }
11050                        }
11051                        '\t' => {
11052                            reindented_line.push('\t');
11053                            spaces_count = 0;
11054                        }
11055                        _ => {
11056                            // Dont append it yet, we might have remaining spaces
11057                            first_non_indent_char = Some(ch);
11058                            break;
11059                        }
11060                    }
11061                }
11062
11063                if !changed {
11064                    reindented_line.clear();
11065                    continue;
11066                }
11067                // Remaining spaces that didn't make a full tab stop
11068                if spaces_count > 0 {
11069                    reindented_line.extend(&space_cache[spaces_count - 1]);
11070                }
11071                // If we consume an extra character that was not indentation, add it back
11072                if let Some(extra_char) = first_non_indent_char {
11073                    reindented_line.push(extra_char);
11074                }
11075                // Append the rest of the line and replace old reference with new one
11076                reindented_line.extend(chars);
11077                *line = Cow::Owned(reindented_line.clone());
11078                reindented_line.clear();
11079            }
11080        });
11081    }
11082
11083    pub fn convert_to_upper_case(
11084        &mut self,
11085        _: &ConvertToUpperCase,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) {
11089        self.manipulate_text(window, cx, |text| text.to_uppercase())
11090    }
11091
11092    pub fn convert_to_lower_case(
11093        &mut self,
11094        _: &ConvertToLowerCase,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        self.manipulate_text(window, cx, |text| text.to_lowercase())
11099    }
11100
11101    pub fn convert_to_title_case(
11102        &mut self,
11103        _: &ConvertToTitleCase,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) {
11107        self.manipulate_text(window, cx, |text| {
11108            text.split('\n')
11109                .map(|line| line.to_case(Case::Title))
11110                .join("\n")
11111        })
11112    }
11113
11114    pub fn convert_to_snake_case(
11115        &mut self,
11116        _: &ConvertToSnakeCase,
11117        window: &mut Window,
11118        cx: &mut Context<Self>,
11119    ) {
11120        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11121    }
11122
11123    pub fn convert_to_kebab_case(
11124        &mut self,
11125        _: &ConvertToKebabCase,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128    ) {
11129        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11130    }
11131
11132    pub fn convert_to_upper_camel_case(
11133        &mut self,
11134        _: &ConvertToUpperCamelCase,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137    ) {
11138        self.manipulate_text(window, cx, |text| {
11139            text.split('\n')
11140                .map(|line| line.to_case(Case::UpperCamel))
11141                .join("\n")
11142        })
11143    }
11144
11145    pub fn convert_to_lower_camel_case(
11146        &mut self,
11147        _: &ConvertToLowerCamelCase,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11152    }
11153
11154    pub fn convert_to_opposite_case(
11155        &mut self,
11156        _: &ConvertToOppositeCase,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        self.manipulate_text(window, cx, |text| {
11161            text.chars()
11162                .fold(String::with_capacity(text.len()), |mut t, c| {
11163                    if c.is_uppercase() {
11164                        t.extend(c.to_lowercase());
11165                    } else {
11166                        t.extend(c.to_uppercase());
11167                    }
11168                    t
11169                })
11170        })
11171    }
11172
11173    pub fn convert_to_sentence_case(
11174        &mut self,
11175        _: &ConvertToSentenceCase,
11176        window: &mut Window,
11177        cx: &mut Context<Self>,
11178    ) {
11179        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11180    }
11181
11182    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11183        self.manipulate_text(window, cx, |text| {
11184            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11185            if has_upper_case_characters {
11186                text.to_lowercase()
11187            } else {
11188                text.to_uppercase()
11189            }
11190        })
11191    }
11192
11193    pub fn convert_to_rot13(
11194        &mut self,
11195        _: &ConvertToRot13,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) {
11199        self.manipulate_text(window, cx, |text| {
11200            text.chars()
11201                .map(|c| match c {
11202                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11203                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11204                    _ => c,
11205                })
11206                .collect()
11207        })
11208    }
11209
11210    pub fn convert_to_rot47(
11211        &mut self,
11212        _: &ConvertToRot47,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        self.manipulate_text(window, cx, |text| {
11217            text.chars()
11218                .map(|c| {
11219                    let code_point = c as u32;
11220                    if code_point >= 33 && code_point <= 126 {
11221                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11222                    }
11223                    c
11224                })
11225                .collect()
11226        })
11227    }
11228
11229    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11230    where
11231        Fn: FnMut(&str) -> String,
11232    {
11233        let buffer = self.buffer.read(cx).snapshot(cx);
11234
11235        let mut new_selections = Vec::new();
11236        let mut edits = Vec::new();
11237        let mut selection_adjustment = 0i32;
11238
11239        for selection in self.selections.all::<usize>(cx) {
11240            let selection_is_empty = selection.is_empty();
11241
11242            let (start, end) = if selection_is_empty {
11243                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11244                (word_range.start, word_range.end)
11245            } else {
11246                (selection.start, selection.end)
11247            };
11248
11249            let text = buffer.text_for_range(start..end).collect::<String>();
11250            let old_length = text.len() as i32;
11251            let text = callback(&text);
11252
11253            new_selections.push(Selection {
11254                start: (start as i32 - selection_adjustment) as usize,
11255                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11256                goal: SelectionGoal::None,
11257                ..selection
11258            });
11259
11260            selection_adjustment += old_length - text.len() as i32;
11261
11262            edits.push((start..end, text));
11263        }
11264
11265        self.transact(window, cx, |this, window, cx| {
11266            this.buffer.update(cx, |buffer, cx| {
11267                buffer.edit(edits, None, cx);
11268            });
11269
11270            this.change_selections(Default::default(), window, cx, |s| {
11271                s.select(new_selections);
11272            });
11273
11274            this.request_autoscroll(Autoscroll::fit(), cx);
11275        });
11276    }
11277
11278    pub fn move_selection_on_drop(
11279        &mut self,
11280        selection: &Selection<Anchor>,
11281        target: DisplayPoint,
11282        is_cut: bool,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11287        let buffer = &display_map.buffer_snapshot;
11288        let mut edits = Vec::new();
11289        let insert_point = display_map
11290            .clip_point(target, Bias::Left)
11291            .to_point(&display_map);
11292        let text = buffer
11293            .text_for_range(selection.start..selection.end)
11294            .collect::<String>();
11295        if is_cut {
11296            edits.push(((selection.start..selection.end), String::new()));
11297        }
11298        let insert_anchor = buffer.anchor_before(insert_point);
11299        edits.push(((insert_anchor..insert_anchor), text));
11300        let last_edit_start = insert_anchor.bias_left(buffer);
11301        let last_edit_end = insert_anchor.bias_right(buffer);
11302        self.transact(window, cx, |this, window, cx| {
11303            this.buffer.update(cx, |buffer, cx| {
11304                buffer.edit(edits, None, cx);
11305            });
11306            this.change_selections(Default::default(), window, cx, |s| {
11307                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11308            });
11309        });
11310    }
11311
11312    pub fn clear_selection_drag_state(&mut self) {
11313        self.selection_drag_state = SelectionDragState::None;
11314    }
11315
11316    pub fn duplicate(
11317        &mut self,
11318        upwards: bool,
11319        whole_lines: bool,
11320        window: &mut Window,
11321        cx: &mut Context<Self>,
11322    ) {
11323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11324
11325        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11326        let buffer = &display_map.buffer_snapshot;
11327        let selections = self.selections.all::<Point>(cx);
11328
11329        let mut edits = Vec::new();
11330        let mut selections_iter = selections.iter().peekable();
11331        while let Some(selection) = selections_iter.next() {
11332            let mut rows = selection.spanned_rows(false, &display_map);
11333            // duplicate line-wise
11334            if whole_lines || selection.start == selection.end {
11335                // Avoid duplicating the same lines twice.
11336                while let Some(next_selection) = selections_iter.peek() {
11337                    let next_rows = next_selection.spanned_rows(false, &display_map);
11338                    if next_rows.start < rows.end {
11339                        rows.end = next_rows.end;
11340                        selections_iter.next().unwrap();
11341                    } else {
11342                        break;
11343                    }
11344                }
11345
11346                // Copy the text from the selected row region and splice it either at the start
11347                // or end of the region.
11348                let start = Point::new(rows.start.0, 0);
11349                let end = Point::new(
11350                    rows.end.previous_row().0,
11351                    buffer.line_len(rows.end.previous_row()),
11352                );
11353                let text = buffer
11354                    .text_for_range(start..end)
11355                    .chain(Some("\n"))
11356                    .collect::<String>();
11357                let insert_location = if upwards {
11358                    Point::new(rows.end.0, 0)
11359                } else {
11360                    start
11361                };
11362                edits.push((insert_location..insert_location, text));
11363            } else {
11364                // duplicate character-wise
11365                let start = selection.start;
11366                let end = selection.end;
11367                let text = buffer.text_for_range(start..end).collect::<String>();
11368                edits.push((selection.end..selection.end, text));
11369            }
11370        }
11371
11372        self.transact(window, cx, |this, _, cx| {
11373            this.buffer.update(cx, |buffer, cx| {
11374                buffer.edit(edits, None, cx);
11375            });
11376
11377            this.request_autoscroll(Autoscroll::fit(), cx);
11378        });
11379    }
11380
11381    pub fn duplicate_line_up(
11382        &mut self,
11383        _: &DuplicateLineUp,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386    ) {
11387        self.duplicate(true, true, window, cx);
11388    }
11389
11390    pub fn duplicate_line_down(
11391        &mut self,
11392        _: &DuplicateLineDown,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        self.duplicate(false, true, window, cx);
11397    }
11398
11399    pub fn duplicate_selection(
11400        &mut self,
11401        _: &DuplicateSelection,
11402        window: &mut Window,
11403        cx: &mut Context<Self>,
11404    ) {
11405        self.duplicate(false, false, window, cx);
11406    }
11407
11408    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11409        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11410        if self.mode.is_single_line() {
11411            cx.propagate();
11412            return;
11413        }
11414
11415        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11416        let buffer = self.buffer.read(cx).snapshot(cx);
11417
11418        let mut edits = Vec::new();
11419        let mut unfold_ranges = Vec::new();
11420        let mut refold_creases = Vec::new();
11421
11422        let selections = self.selections.all::<Point>(cx);
11423        let mut selections = selections.iter().peekable();
11424        let mut contiguous_row_selections = Vec::new();
11425        let mut new_selections = Vec::new();
11426
11427        while let Some(selection) = selections.next() {
11428            // Find all the selections that span a contiguous row range
11429            let (start_row, end_row) = consume_contiguous_rows(
11430                &mut contiguous_row_selections,
11431                selection,
11432                &display_map,
11433                &mut selections,
11434            );
11435
11436            // Move the text spanned by the row range to be before the line preceding the row range
11437            if start_row.0 > 0 {
11438                let range_to_move = Point::new(
11439                    start_row.previous_row().0,
11440                    buffer.line_len(start_row.previous_row()),
11441                )
11442                    ..Point::new(
11443                        end_row.previous_row().0,
11444                        buffer.line_len(end_row.previous_row()),
11445                    );
11446                let insertion_point = display_map
11447                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11448                    .0;
11449
11450                // Don't move lines across excerpts
11451                if buffer
11452                    .excerpt_containing(insertion_point..range_to_move.end)
11453                    .is_some()
11454                {
11455                    let text = buffer
11456                        .text_for_range(range_to_move.clone())
11457                        .flat_map(|s| s.chars())
11458                        .skip(1)
11459                        .chain(['\n'])
11460                        .collect::<String>();
11461
11462                    edits.push((
11463                        buffer.anchor_after(range_to_move.start)
11464                            ..buffer.anchor_before(range_to_move.end),
11465                        String::new(),
11466                    ));
11467                    let insertion_anchor = buffer.anchor_after(insertion_point);
11468                    edits.push((insertion_anchor..insertion_anchor, text));
11469
11470                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11471
11472                    // Move selections up
11473                    new_selections.extend(contiguous_row_selections.drain(..).map(
11474                        |mut selection| {
11475                            selection.start.row -= row_delta;
11476                            selection.end.row -= row_delta;
11477                            selection
11478                        },
11479                    ));
11480
11481                    // Move folds up
11482                    unfold_ranges.push(range_to_move.clone());
11483                    for fold in display_map.folds_in_range(
11484                        buffer.anchor_before(range_to_move.start)
11485                            ..buffer.anchor_after(range_to_move.end),
11486                    ) {
11487                        let mut start = fold.range.start.to_point(&buffer);
11488                        let mut end = fold.range.end.to_point(&buffer);
11489                        start.row -= row_delta;
11490                        end.row -= row_delta;
11491                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11492                    }
11493                }
11494            }
11495
11496            // If we didn't move line(s), preserve the existing selections
11497            new_selections.append(&mut contiguous_row_selections);
11498        }
11499
11500        self.transact(window, cx, |this, window, cx| {
11501            this.unfold_ranges(&unfold_ranges, true, true, cx);
11502            this.buffer.update(cx, |buffer, cx| {
11503                for (range, text) in edits {
11504                    buffer.edit([(range, text)], None, cx);
11505                }
11506            });
11507            this.fold_creases(refold_creases, true, window, cx);
11508            this.change_selections(Default::default(), window, cx, |s| {
11509                s.select(new_selections);
11510            })
11511        });
11512    }
11513
11514    pub fn move_line_down(
11515        &mut self,
11516        _: &MoveLineDown,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11521        if self.mode.is_single_line() {
11522            cx.propagate();
11523            return;
11524        }
11525
11526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11527        let buffer = self.buffer.read(cx).snapshot(cx);
11528
11529        let mut edits = Vec::new();
11530        let mut unfold_ranges = Vec::new();
11531        let mut refold_creases = Vec::new();
11532
11533        let selections = self.selections.all::<Point>(cx);
11534        let mut selections = selections.iter().peekable();
11535        let mut contiguous_row_selections = Vec::new();
11536        let mut new_selections = Vec::new();
11537
11538        while let Some(selection) = selections.next() {
11539            // Find all the selections that span a contiguous row range
11540            let (start_row, end_row) = consume_contiguous_rows(
11541                &mut contiguous_row_selections,
11542                selection,
11543                &display_map,
11544                &mut selections,
11545            );
11546
11547            // Move the text spanned by the row range to be after the last line of the row range
11548            if end_row.0 <= buffer.max_point().row {
11549                let range_to_move =
11550                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11551                let insertion_point = display_map
11552                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11553                    .0;
11554
11555                // Don't move lines across excerpt boundaries
11556                if buffer
11557                    .excerpt_containing(range_to_move.start..insertion_point)
11558                    .is_some()
11559                {
11560                    let mut text = String::from("\n");
11561                    text.extend(buffer.text_for_range(range_to_move.clone()));
11562                    text.pop(); // Drop trailing newline
11563                    edits.push((
11564                        buffer.anchor_after(range_to_move.start)
11565                            ..buffer.anchor_before(range_to_move.end),
11566                        String::new(),
11567                    ));
11568                    let insertion_anchor = buffer.anchor_after(insertion_point);
11569                    edits.push((insertion_anchor..insertion_anchor, text));
11570
11571                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11572
11573                    // Move selections down
11574                    new_selections.extend(contiguous_row_selections.drain(..).map(
11575                        |mut selection| {
11576                            selection.start.row += row_delta;
11577                            selection.end.row += row_delta;
11578                            selection
11579                        },
11580                    ));
11581
11582                    // Move folds down
11583                    unfold_ranges.push(range_to_move.clone());
11584                    for fold in display_map.folds_in_range(
11585                        buffer.anchor_before(range_to_move.start)
11586                            ..buffer.anchor_after(range_to_move.end),
11587                    ) {
11588                        let mut start = fold.range.start.to_point(&buffer);
11589                        let mut end = fold.range.end.to_point(&buffer);
11590                        start.row += row_delta;
11591                        end.row += row_delta;
11592                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11593                    }
11594                }
11595            }
11596
11597            // If we didn't move line(s), preserve the existing selections
11598            new_selections.append(&mut contiguous_row_selections);
11599        }
11600
11601        self.transact(window, cx, |this, window, cx| {
11602            this.unfold_ranges(&unfold_ranges, true, true, cx);
11603            this.buffer.update(cx, |buffer, cx| {
11604                for (range, text) in edits {
11605                    buffer.edit([(range, text)], None, cx);
11606                }
11607            });
11608            this.fold_creases(refold_creases, true, window, cx);
11609            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11610        });
11611    }
11612
11613    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11615        let text_layout_details = &self.text_layout_details(window);
11616        self.transact(window, cx, |this, window, cx| {
11617            let edits = this.change_selections(Default::default(), window, cx, |s| {
11618                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11619                s.move_with(|display_map, selection| {
11620                    if !selection.is_empty() {
11621                        return;
11622                    }
11623
11624                    let mut head = selection.head();
11625                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11626                    if head.column() == display_map.line_len(head.row()) {
11627                        transpose_offset = display_map
11628                            .buffer_snapshot
11629                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11630                    }
11631
11632                    if transpose_offset == 0 {
11633                        return;
11634                    }
11635
11636                    *head.column_mut() += 1;
11637                    head = display_map.clip_point(head, Bias::Right);
11638                    let goal = SelectionGoal::HorizontalPosition(
11639                        display_map
11640                            .x_for_display_point(head, text_layout_details)
11641                            .into(),
11642                    );
11643                    selection.collapse_to(head, goal);
11644
11645                    let transpose_start = display_map
11646                        .buffer_snapshot
11647                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11648                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11649                        let transpose_end = display_map
11650                            .buffer_snapshot
11651                            .clip_offset(transpose_offset + 1, Bias::Right);
11652                        if let Some(ch) =
11653                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11654                        {
11655                            edits.push((transpose_start..transpose_offset, String::new()));
11656                            edits.push((transpose_end..transpose_end, ch.to_string()));
11657                        }
11658                    }
11659                });
11660                edits
11661            });
11662            this.buffer
11663                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11664            let selections = this.selections.all::<usize>(cx);
11665            this.change_selections(Default::default(), window, cx, |s| {
11666                s.select(selections);
11667            });
11668        });
11669    }
11670
11671    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11673        if self.mode.is_single_line() {
11674            cx.propagate();
11675            return;
11676        }
11677
11678        self.rewrap_impl(RewrapOptions::default(), cx)
11679    }
11680
11681    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11682        let buffer = self.buffer.read(cx).snapshot(cx);
11683        let selections = self.selections.all::<Point>(cx);
11684
11685        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11686        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11687            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11688                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11689                .peekable();
11690
11691            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11692                row
11693            } else {
11694                return Vec::new();
11695            };
11696
11697            let language_settings = buffer.language_settings_at(selection.head(), cx);
11698            let language_scope = buffer.language_scope_at(selection.head());
11699
11700            let indent_and_prefix_for_row =
11701                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11702                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11703                    let (comment_prefix, rewrap_prefix) =
11704                        if let Some(language_scope) = &language_scope {
11705                            let indent_end = Point::new(row, indent.len);
11706                            let comment_prefix = language_scope
11707                                .line_comment_prefixes()
11708                                .iter()
11709                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11710                                .map(|prefix| prefix.to_string());
11711                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11712                            let line_text_after_indent = buffer
11713                                .text_for_range(indent_end..line_end)
11714                                .collect::<String>();
11715                            let rewrap_prefix = language_scope
11716                                .rewrap_prefixes()
11717                                .iter()
11718                                .find_map(|prefix_regex| {
11719                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11720                                        if mat.start() == 0 {
11721                                            Some(mat.as_str().to_string())
11722                                        } else {
11723                                            None
11724                                        }
11725                                    })
11726                                })
11727                                .flatten();
11728                            (comment_prefix, rewrap_prefix)
11729                        } else {
11730                            (None, None)
11731                        };
11732                    (indent, comment_prefix, rewrap_prefix)
11733                };
11734
11735            let mut ranges = Vec::new();
11736            let from_empty_selection = selection.is_empty();
11737
11738            let mut current_range_start = first_row;
11739            let mut prev_row = first_row;
11740            let (
11741                mut current_range_indent,
11742                mut current_range_comment_prefix,
11743                mut current_range_rewrap_prefix,
11744            ) = indent_and_prefix_for_row(first_row);
11745
11746            for row in non_blank_rows_iter.skip(1) {
11747                let has_paragraph_break = row > prev_row + 1;
11748
11749                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11750                    indent_and_prefix_for_row(row);
11751
11752                let has_indent_change = row_indent != current_range_indent;
11753                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11754
11755                let has_boundary_change = has_comment_change
11756                    || row_rewrap_prefix.is_some()
11757                    || (has_indent_change && current_range_comment_prefix.is_some());
11758
11759                if has_paragraph_break || has_boundary_change {
11760                    ranges.push((
11761                        language_settings.clone(),
11762                        Point::new(current_range_start, 0)
11763                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11764                        current_range_indent,
11765                        current_range_comment_prefix.clone(),
11766                        current_range_rewrap_prefix.clone(),
11767                        from_empty_selection,
11768                    ));
11769                    current_range_start = row;
11770                    current_range_indent = row_indent;
11771                    current_range_comment_prefix = row_comment_prefix;
11772                    current_range_rewrap_prefix = row_rewrap_prefix;
11773                }
11774                prev_row = row;
11775            }
11776
11777            ranges.push((
11778                language_settings.clone(),
11779                Point::new(current_range_start, 0)
11780                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11781                current_range_indent,
11782                current_range_comment_prefix,
11783                current_range_rewrap_prefix,
11784                from_empty_selection,
11785            ));
11786
11787            ranges
11788        });
11789
11790        let mut edits = Vec::new();
11791        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11792
11793        for (
11794            language_settings,
11795            wrap_range,
11796            indent_size,
11797            comment_prefix,
11798            rewrap_prefix,
11799            from_empty_selection,
11800        ) in wrap_ranges
11801        {
11802            let mut start_row = wrap_range.start.row;
11803            let mut end_row = wrap_range.end.row;
11804
11805            // Skip selections that overlap with a range that has already been rewrapped.
11806            let selection_range = start_row..end_row;
11807            if rewrapped_row_ranges
11808                .iter()
11809                .any(|range| range.overlaps(&selection_range))
11810            {
11811                continue;
11812            }
11813
11814            let tab_size = language_settings.tab_size;
11815
11816            let indent_prefix = indent_size.chars().collect::<String>();
11817            let mut line_prefix = indent_prefix.clone();
11818            let mut inside_comment = false;
11819            if let Some(prefix) = &comment_prefix {
11820                line_prefix.push_str(prefix);
11821                inside_comment = true;
11822            }
11823            if let Some(prefix) = &rewrap_prefix {
11824                line_prefix.push_str(prefix);
11825            }
11826
11827            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11828                RewrapBehavior::InComments => inside_comment,
11829                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11830                RewrapBehavior::Anywhere => true,
11831            };
11832
11833            let should_rewrap = options.override_language_settings
11834                || allow_rewrap_based_on_language
11835                || self.hard_wrap.is_some();
11836            if !should_rewrap {
11837                continue;
11838            }
11839
11840            if from_empty_selection {
11841                'expand_upwards: while start_row > 0 {
11842                    let prev_row = start_row - 1;
11843                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11844                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11845                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11846                    {
11847                        start_row = prev_row;
11848                    } else {
11849                        break 'expand_upwards;
11850                    }
11851                }
11852
11853                'expand_downwards: while end_row < buffer.max_point().row {
11854                    let next_row = end_row + 1;
11855                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11856                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11857                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11858                    {
11859                        end_row = next_row;
11860                    } else {
11861                        break 'expand_downwards;
11862                    }
11863                }
11864            }
11865
11866            let start = Point::new(start_row, 0);
11867            let start_offset = start.to_offset(&buffer);
11868            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11869            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11870            let Some(lines_without_prefixes) = selection_text
11871                .lines()
11872                .enumerate()
11873                .map(|(ix, line)| {
11874                    let line_trimmed = line.trim_start();
11875                    if rewrap_prefix.is_some() && ix > 0 {
11876                        Ok(line_trimmed)
11877                    } else {
11878                        line_trimmed
11879                            .strip_prefix(&line_prefix.trim_start())
11880                            .with_context(|| {
11881                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11882                            })
11883                    }
11884                })
11885                .collect::<Result<Vec<_>, _>>()
11886                .log_err()
11887            else {
11888                continue;
11889            };
11890
11891            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11892                buffer
11893                    .language_settings_at(Point::new(start_row, 0), cx)
11894                    .preferred_line_length as usize
11895            });
11896
11897            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11898                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11899            } else {
11900                line_prefix.clone()
11901            };
11902
11903            let wrapped_text = wrap_with_prefix(
11904                line_prefix,
11905                subsequent_lines_prefix,
11906                lines_without_prefixes.join("\n"),
11907                wrap_column,
11908                tab_size,
11909                options.preserve_existing_whitespace,
11910            );
11911
11912            // TODO: should always use char-based diff while still supporting cursor behavior that
11913            // matches vim.
11914            let mut diff_options = DiffOptions::default();
11915            if options.override_language_settings {
11916                diff_options.max_word_diff_len = 0;
11917                diff_options.max_word_diff_line_count = 0;
11918            } else {
11919                diff_options.max_word_diff_len = usize::MAX;
11920                diff_options.max_word_diff_line_count = usize::MAX;
11921            }
11922
11923            for (old_range, new_text) in
11924                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11925            {
11926                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11927                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11928                edits.push((edit_start..edit_end, new_text));
11929            }
11930
11931            rewrapped_row_ranges.push(start_row..=end_row);
11932        }
11933
11934        self.buffer
11935            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11936    }
11937
11938    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11939        let mut text = String::new();
11940        let buffer = self.buffer.read(cx).snapshot(cx);
11941        let mut selections = self.selections.all::<Point>(cx);
11942        let mut clipboard_selections = Vec::with_capacity(selections.len());
11943        {
11944            let max_point = buffer.max_point();
11945            let mut is_first = true;
11946            for selection in &mut selections {
11947                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11948                if is_entire_line {
11949                    selection.start = Point::new(selection.start.row, 0);
11950                    if !selection.is_empty() && selection.end.column == 0 {
11951                        selection.end = cmp::min(max_point, selection.end);
11952                    } else {
11953                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11954                    }
11955                    selection.goal = SelectionGoal::None;
11956                }
11957                if is_first {
11958                    is_first = false;
11959                } else {
11960                    text += "\n";
11961                }
11962                let mut len = 0;
11963                for chunk in buffer.text_for_range(selection.start..selection.end) {
11964                    text.push_str(chunk);
11965                    len += chunk.len();
11966                }
11967                clipboard_selections.push(ClipboardSelection {
11968                    len,
11969                    is_entire_line,
11970                    first_line_indent: buffer
11971                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11972                        .len,
11973                });
11974            }
11975        }
11976
11977        self.transact(window, cx, |this, window, cx| {
11978            this.change_selections(Default::default(), window, cx, |s| {
11979                s.select(selections);
11980            });
11981            this.insert("", window, cx);
11982        });
11983        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11984    }
11985
11986    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11988        let item = self.cut_common(window, cx);
11989        cx.write_to_clipboard(item);
11990    }
11991
11992    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11994        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11995            s.move_with(|snapshot, sel| {
11996                if sel.is_empty() {
11997                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11998                }
11999            });
12000        });
12001        let item = self.cut_common(window, cx);
12002        cx.set_global(KillRing(item))
12003    }
12004
12005    pub fn kill_ring_yank(
12006        &mut self,
12007        _: &KillRingYank,
12008        window: &mut Window,
12009        cx: &mut Context<Self>,
12010    ) {
12011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12012        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12013            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12014                (kill_ring.text().to_string(), kill_ring.metadata_json())
12015            } else {
12016                return;
12017            }
12018        } else {
12019            return;
12020        };
12021        self.do_paste(&text, metadata, false, window, cx);
12022    }
12023
12024    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12025        self.do_copy(true, cx);
12026    }
12027
12028    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12029        self.do_copy(false, cx);
12030    }
12031
12032    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12033        let selections = self.selections.all::<Point>(cx);
12034        let buffer = self.buffer.read(cx).read(cx);
12035        let mut text = String::new();
12036
12037        let mut clipboard_selections = Vec::with_capacity(selections.len());
12038        {
12039            let max_point = buffer.max_point();
12040            let mut is_first = true;
12041            for selection in &selections {
12042                let mut start = selection.start;
12043                let mut end = selection.end;
12044                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12045                if is_entire_line {
12046                    start = Point::new(start.row, 0);
12047                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12048                }
12049
12050                let mut trimmed_selections = Vec::new();
12051                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12052                    let row = MultiBufferRow(start.row);
12053                    let first_indent = buffer.indent_size_for_line(row);
12054                    if first_indent.len == 0 || start.column > first_indent.len {
12055                        trimmed_selections.push(start..end);
12056                    } else {
12057                        trimmed_selections.push(
12058                            Point::new(row.0, first_indent.len)
12059                                ..Point::new(row.0, buffer.line_len(row)),
12060                        );
12061                        for row in start.row + 1..=end.row {
12062                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12063                            if row == end.row {
12064                                line_len = end.column;
12065                            }
12066                            if line_len == 0 {
12067                                trimmed_selections
12068                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12069                                continue;
12070                            }
12071                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12072                            if row_indent_size.len >= first_indent.len {
12073                                trimmed_selections.push(
12074                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12075                                );
12076                            } else {
12077                                trimmed_selections.clear();
12078                                trimmed_selections.push(start..end);
12079                                break;
12080                            }
12081                        }
12082                    }
12083                } else {
12084                    trimmed_selections.push(start..end);
12085                }
12086
12087                for trimmed_range in trimmed_selections {
12088                    if is_first {
12089                        is_first = false;
12090                    } else {
12091                        text += "\n";
12092                    }
12093                    let mut len = 0;
12094                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12095                        text.push_str(chunk);
12096                        len += chunk.len();
12097                    }
12098                    clipboard_selections.push(ClipboardSelection {
12099                        len,
12100                        is_entire_line,
12101                        first_line_indent: buffer
12102                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12103                            .len,
12104                    });
12105                }
12106            }
12107        }
12108
12109        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12110            text,
12111            clipboard_selections,
12112        ));
12113    }
12114
12115    pub fn do_paste(
12116        &mut self,
12117        text: &String,
12118        clipboard_selections: Option<Vec<ClipboardSelection>>,
12119        handle_entire_lines: bool,
12120        window: &mut Window,
12121        cx: &mut Context<Self>,
12122    ) {
12123        if self.read_only(cx) {
12124            return;
12125        }
12126
12127        let clipboard_text = Cow::Borrowed(text);
12128
12129        self.transact(window, cx, |this, window, cx| {
12130            if let Some(mut clipboard_selections) = clipboard_selections {
12131                let old_selections = this.selections.all::<usize>(cx);
12132                let all_selections_were_entire_line =
12133                    clipboard_selections.iter().all(|s| s.is_entire_line);
12134                let first_selection_indent_column =
12135                    clipboard_selections.first().map(|s| s.first_line_indent);
12136                if clipboard_selections.len() != old_selections.len() {
12137                    clipboard_selections.drain(..);
12138                }
12139                let cursor_offset = this.selections.last::<usize>(cx).head();
12140                let mut auto_indent_on_paste = true;
12141
12142                this.buffer.update(cx, |buffer, cx| {
12143                    let snapshot = buffer.read(cx);
12144                    auto_indent_on_paste = snapshot
12145                        .language_settings_at(cursor_offset, cx)
12146                        .auto_indent_on_paste;
12147
12148                    let mut start_offset = 0;
12149                    let mut edits = Vec::new();
12150                    let mut original_indent_columns = Vec::new();
12151                    for (ix, selection) in old_selections.iter().enumerate() {
12152                        let to_insert;
12153                        let entire_line;
12154                        let original_indent_column;
12155                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12156                            let end_offset = start_offset + clipboard_selection.len;
12157                            to_insert = &clipboard_text[start_offset..end_offset];
12158                            entire_line = clipboard_selection.is_entire_line;
12159                            start_offset = end_offset + 1;
12160                            original_indent_column = Some(clipboard_selection.first_line_indent);
12161                        } else {
12162                            to_insert = clipboard_text.as_str();
12163                            entire_line = all_selections_were_entire_line;
12164                            original_indent_column = first_selection_indent_column
12165                        }
12166
12167                        // If the corresponding selection was empty when this slice of the
12168                        // clipboard text was written, then the entire line containing the
12169                        // selection was copied. If this selection is also currently empty,
12170                        // then paste the line before the current line of the buffer.
12171                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12172                            let column = selection.start.to_point(&snapshot).column as usize;
12173                            let line_start = selection.start - column;
12174                            line_start..line_start
12175                        } else {
12176                            selection.range()
12177                        };
12178
12179                        edits.push((range, to_insert));
12180                        original_indent_columns.push(original_indent_column);
12181                    }
12182                    drop(snapshot);
12183
12184                    buffer.edit(
12185                        edits,
12186                        if auto_indent_on_paste {
12187                            Some(AutoindentMode::Block {
12188                                original_indent_columns,
12189                            })
12190                        } else {
12191                            None
12192                        },
12193                        cx,
12194                    );
12195                });
12196
12197                let selections = this.selections.all::<usize>(cx);
12198                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12199            } else {
12200                this.insert(&clipboard_text, window, cx);
12201            }
12202        });
12203    }
12204
12205    pub fn diff_clipboard_with_selection(
12206        &mut self,
12207        _: &DiffClipboardWithSelection,
12208        window: &mut Window,
12209        cx: &mut Context<Self>,
12210    ) {
12211        let selections = self.selections.all::<usize>(cx);
12212
12213        if selections.is_empty() {
12214            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12215            return;
12216        };
12217
12218        let clipboard_text = match cx.read_from_clipboard() {
12219            Some(item) => match item.entries().first() {
12220                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12221                _ => None,
12222            },
12223            None => None,
12224        };
12225
12226        let Some(clipboard_text) = clipboard_text else {
12227            log::warn!("Clipboard doesn't contain text.");
12228            return;
12229        };
12230
12231        window.dispatch_action(
12232            Box::new(DiffClipboardWithSelectionData {
12233                clipboard_text,
12234                editor: cx.entity(),
12235            }),
12236            cx,
12237        );
12238    }
12239
12240    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12242        if let Some(item) = cx.read_from_clipboard() {
12243            let entries = item.entries();
12244
12245            match entries.first() {
12246                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12247                // of all the pasted entries.
12248                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12249                    .do_paste(
12250                        clipboard_string.text(),
12251                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12252                        true,
12253                        window,
12254                        cx,
12255                    ),
12256                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12257            }
12258        }
12259    }
12260
12261    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12262        if self.read_only(cx) {
12263            return;
12264        }
12265
12266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12267
12268        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12269            if let Some((selections, _)) =
12270                self.selection_history.transaction(transaction_id).cloned()
12271            {
12272                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12273                    s.select_anchors(selections.to_vec());
12274                });
12275            } else {
12276                log::error!(
12277                    "No entry in selection_history found for undo. \
12278                     This may correspond to a bug where undo does not update the selection. \
12279                     If this is occurring, please add details to \
12280                     https://github.com/zed-industries/zed/issues/22692"
12281                );
12282            }
12283            self.request_autoscroll(Autoscroll::fit(), cx);
12284            self.unmark_text(window, cx);
12285            self.refresh_inline_completion(true, false, window, cx);
12286            cx.emit(EditorEvent::Edited { transaction_id });
12287            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12288        }
12289    }
12290
12291    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12292        if self.read_only(cx) {
12293            return;
12294        }
12295
12296        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12297
12298        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12299            if let Some((_, Some(selections))) =
12300                self.selection_history.transaction(transaction_id).cloned()
12301            {
12302                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12303                    s.select_anchors(selections.to_vec());
12304                });
12305            } else {
12306                log::error!(
12307                    "No entry in selection_history found for redo. \
12308                     This may correspond to a bug where undo does not update the selection. \
12309                     If this is occurring, please add details to \
12310                     https://github.com/zed-industries/zed/issues/22692"
12311                );
12312            }
12313            self.request_autoscroll(Autoscroll::fit(), cx);
12314            self.unmark_text(window, cx);
12315            self.refresh_inline_completion(true, false, window, cx);
12316            cx.emit(EditorEvent::Edited { transaction_id });
12317        }
12318    }
12319
12320    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12321        self.buffer
12322            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12323    }
12324
12325    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12326        self.buffer
12327            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12328    }
12329
12330    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12332        self.change_selections(Default::default(), window, cx, |s| {
12333            s.move_with(|map, selection| {
12334                let cursor = if selection.is_empty() {
12335                    movement::left(map, selection.start)
12336                } else {
12337                    selection.start
12338                };
12339                selection.collapse_to(cursor, SelectionGoal::None);
12340            });
12341        })
12342    }
12343
12344    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12346        self.change_selections(Default::default(), window, cx, |s| {
12347            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12348        })
12349    }
12350
12351    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12353        self.change_selections(Default::default(), window, cx, |s| {
12354            s.move_with(|map, selection| {
12355                let cursor = if selection.is_empty() {
12356                    movement::right(map, selection.end)
12357                } else {
12358                    selection.end
12359                };
12360                selection.collapse_to(cursor, SelectionGoal::None)
12361            });
12362        })
12363    }
12364
12365    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12367        self.change_selections(Default::default(), window, cx, |s| {
12368            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12369        })
12370    }
12371
12372    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12373        if self.take_rename(true, window, cx).is_some() {
12374            return;
12375        }
12376
12377        if self.mode.is_single_line() {
12378            cx.propagate();
12379            return;
12380        }
12381
12382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12383
12384        let text_layout_details = &self.text_layout_details(window);
12385        let selection_count = self.selections.count();
12386        let first_selection = self.selections.first_anchor();
12387
12388        self.change_selections(Default::default(), window, cx, |s| {
12389            s.move_with(|map, selection| {
12390                if !selection.is_empty() {
12391                    selection.goal = SelectionGoal::None;
12392                }
12393                let (cursor, goal) = movement::up(
12394                    map,
12395                    selection.start,
12396                    selection.goal,
12397                    false,
12398                    text_layout_details,
12399                );
12400                selection.collapse_to(cursor, goal);
12401            });
12402        });
12403
12404        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12405        {
12406            cx.propagate();
12407        }
12408    }
12409
12410    pub fn move_up_by_lines(
12411        &mut self,
12412        action: &MoveUpByLines,
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::up_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 move_down_by_lines(
12448        &mut self,
12449        action: &MoveDownByLines,
12450        window: &mut Window,
12451        cx: &mut Context<Self>,
12452    ) {
12453        if self.take_rename(true, window, cx).is_some() {
12454            return;
12455        }
12456
12457        if self.mode.is_single_line() {
12458            cx.propagate();
12459            return;
12460        }
12461
12462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12463
12464        let text_layout_details = &self.text_layout_details(window);
12465
12466        self.change_selections(Default::default(), window, cx, |s| {
12467            s.move_with(|map, selection| {
12468                if !selection.is_empty() {
12469                    selection.goal = SelectionGoal::None;
12470                }
12471                let (cursor, goal) = movement::down_by_rows(
12472                    map,
12473                    selection.start,
12474                    action.lines,
12475                    selection.goal,
12476                    false,
12477                    text_layout_details,
12478                );
12479                selection.collapse_to(cursor, goal);
12480            });
12481        })
12482    }
12483
12484    pub fn select_down_by_lines(
12485        &mut self,
12486        action: &SelectDownByLines,
12487        window: &mut Window,
12488        cx: &mut Context<Self>,
12489    ) {
12490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12491        let text_layout_details = &self.text_layout_details(window);
12492        self.change_selections(Default::default(), window, cx, |s| {
12493            s.move_heads_with(|map, head, goal| {
12494                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12495            })
12496        })
12497    }
12498
12499    pub fn select_up_by_lines(
12500        &mut self,
12501        action: &SelectUpByLines,
12502        window: &mut Window,
12503        cx: &mut Context<Self>,
12504    ) {
12505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12506        let text_layout_details = &self.text_layout_details(window);
12507        self.change_selections(Default::default(), window, cx, |s| {
12508            s.move_heads_with(|map, head, goal| {
12509                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12510            })
12511        })
12512    }
12513
12514    pub fn select_page_up(
12515        &mut self,
12516        _: &SelectPageUp,
12517        window: &mut Window,
12518        cx: &mut Context<Self>,
12519    ) {
12520        let Some(row_count) = self.visible_row_count() else {
12521            return;
12522        };
12523
12524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12525
12526        let text_layout_details = &self.text_layout_details(window);
12527
12528        self.change_selections(Default::default(), window, cx, |s| {
12529            s.move_heads_with(|map, head, goal| {
12530                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12531            })
12532        })
12533    }
12534
12535    pub fn move_page_up(
12536        &mut self,
12537        action: &MovePageUp,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        if self.take_rename(true, window, cx).is_some() {
12542            return;
12543        }
12544
12545        if self
12546            .context_menu
12547            .borrow_mut()
12548            .as_mut()
12549            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12550            .unwrap_or(false)
12551        {
12552            return;
12553        }
12554
12555        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12556            cx.propagate();
12557            return;
12558        }
12559
12560        let Some(row_count) = self.visible_row_count() else {
12561            return;
12562        };
12563
12564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12565
12566        let effects = if action.center_cursor {
12567            SelectionEffects::scroll(Autoscroll::center())
12568        } else {
12569            SelectionEffects::default()
12570        };
12571
12572        let text_layout_details = &self.text_layout_details(window);
12573
12574        self.change_selections(effects, window, cx, |s| {
12575            s.move_with(|map, selection| {
12576                if !selection.is_empty() {
12577                    selection.goal = SelectionGoal::None;
12578                }
12579                let (cursor, goal) = movement::up_by_rows(
12580                    map,
12581                    selection.end,
12582                    row_count,
12583                    selection.goal,
12584                    false,
12585                    text_layout_details,
12586                );
12587                selection.collapse_to(cursor, goal);
12588            });
12589        });
12590    }
12591
12592    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12594        let text_layout_details = &self.text_layout_details(window);
12595        self.change_selections(Default::default(), window, cx, |s| {
12596            s.move_heads_with(|map, head, goal| {
12597                movement::up(map, head, goal, false, text_layout_details)
12598            })
12599        })
12600    }
12601
12602    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12603        self.take_rename(true, window, cx);
12604
12605        if self.mode.is_single_line() {
12606            cx.propagate();
12607            return;
12608        }
12609
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12611
12612        let text_layout_details = &self.text_layout_details(window);
12613        let selection_count = self.selections.count();
12614        let first_selection = self.selections.first_anchor();
12615
12616        self.change_selections(Default::default(), window, cx, |s| {
12617            s.move_with(|map, selection| {
12618                if !selection.is_empty() {
12619                    selection.goal = SelectionGoal::None;
12620                }
12621                let (cursor, goal) = movement::down(
12622                    map,
12623                    selection.end,
12624                    selection.goal,
12625                    false,
12626                    text_layout_details,
12627                );
12628                selection.collapse_to(cursor, goal);
12629            });
12630        });
12631
12632        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12633        {
12634            cx.propagate();
12635        }
12636    }
12637
12638    pub fn select_page_down(
12639        &mut self,
12640        _: &SelectPageDown,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        let Some(row_count) = self.visible_row_count() else {
12645            return;
12646        };
12647
12648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12649
12650        let text_layout_details = &self.text_layout_details(window);
12651
12652        self.change_selections(Default::default(), window, cx, |s| {
12653            s.move_heads_with(|map, head, goal| {
12654                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12655            })
12656        })
12657    }
12658
12659    pub fn move_page_down(
12660        &mut self,
12661        action: &MovePageDown,
12662        window: &mut Window,
12663        cx: &mut Context<Self>,
12664    ) {
12665        if self.take_rename(true, window, cx).is_some() {
12666            return;
12667        }
12668
12669        if self
12670            .context_menu
12671            .borrow_mut()
12672            .as_mut()
12673            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12674            .unwrap_or(false)
12675        {
12676            return;
12677        }
12678
12679        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12680            cx.propagate();
12681            return;
12682        }
12683
12684        let Some(row_count) = self.visible_row_count() else {
12685            return;
12686        };
12687
12688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12689
12690        let effects = if action.center_cursor {
12691            SelectionEffects::scroll(Autoscroll::center())
12692        } else {
12693            SelectionEffects::default()
12694        };
12695
12696        let text_layout_details = &self.text_layout_details(window);
12697        self.change_selections(effects, window, cx, |s| {
12698            s.move_with(|map, selection| {
12699                if !selection.is_empty() {
12700                    selection.goal = SelectionGoal::None;
12701                }
12702                let (cursor, goal) = movement::down_by_rows(
12703                    map,
12704                    selection.end,
12705                    row_count,
12706                    selection.goal,
12707                    false,
12708                    text_layout_details,
12709                );
12710                selection.collapse_to(cursor, goal);
12711            });
12712        });
12713    }
12714
12715    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12717        let text_layout_details = &self.text_layout_details(window);
12718        self.change_selections(Default::default(), window, cx, |s| {
12719            s.move_heads_with(|map, head, goal| {
12720                movement::down(map, head, goal, false, text_layout_details)
12721            })
12722        });
12723    }
12724
12725    pub fn context_menu_first(
12726        &mut self,
12727        _: &ContextMenuFirst,
12728        window: &mut Window,
12729        cx: &mut Context<Self>,
12730    ) {
12731        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12732            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12733        }
12734    }
12735
12736    pub fn context_menu_prev(
12737        &mut self,
12738        _: &ContextMenuPrevious,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) {
12742        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12743            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12744        }
12745    }
12746
12747    pub fn context_menu_next(
12748        &mut self,
12749        _: &ContextMenuNext,
12750        window: &mut Window,
12751        cx: &mut Context<Self>,
12752    ) {
12753        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12754            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12755        }
12756    }
12757
12758    pub fn context_menu_last(
12759        &mut self,
12760        _: &ContextMenuLast,
12761        window: &mut Window,
12762        cx: &mut Context<Self>,
12763    ) {
12764        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12765            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12766        }
12767    }
12768
12769    pub fn signature_help_prev(
12770        &mut self,
12771        _: &SignatureHelpPrevious,
12772        _: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) {
12775        if let Some(popover) = self.signature_help_state.popover_mut() {
12776            if popover.current_signature == 0 {
12777                popover.current_signature = popover.signatures.len() - 1;
12778            } else {
12779                popover.current_signature -= 1;
12780            }
12781            cx.notify();
12782        }
12783    }
12784
12785    pub fn signature_help_next(
12786        &mut self,
12787        _: &SignatureHelpNext,
12788        _: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) {
12791        if let Some(popover) = self.signature_help_state.popover_mut() {
12792            if popover.current_signature + 1 == popover.signatures.len() {
12793                popover.current_signature = 0;
12794            } else {
12795                popover.current_signature += 1;
12796            }
12797            cx.notify();
12798        }
12799    }
12800
12801    pub fn move_to_previous_word_start(
12802        &mut self,
12803        _: &MoveToPreviousWordStart,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12808        self.change_selections(Default::default(), window, cx, |s| {
12809            s.move_cursors_with(|map, head, _| {
12810                (
12811                    movement::previous_word_start(map, head),
12812                    SelectionGoal::None,
12813                )
12814            });
12815        })
12816    }
12817
12818    pub fn move_to_previous_subword_start(
12819        &mut self,
12820        _: &MoveToPreviousSubwordStart,
12821        window: &mut Window,
12822        cx: &mut Context<Self>,
12823    ) {
12824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12825        self.change_selections(Default::default(), window, cx, |s| {
12826            s.move_cursors_with(|map, head, _| {
12827                (
12828                    movement::previous_subword_start(map, head),
12829                    SelectionGoal::None,
12830                )
12831            });
12832        })
12833    }
12834
12835    pub fn select_to_previous_word_start(
12836        &mut self,
12837        _: &SelectToPreviousWordStart,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12842        self.change_selections(Default::default(), window, cx, |s| {
12843            s.move_heads_with(|map, head, _| {
12844                (
12845                    movement::previous_word_start(map, head),
12846                    SelectionGoal::None,
12847                )
12848            });
12849        })
12850    }
12851
12852    pub fn select_to_previous_subword_start(
12853        &mut self,
12854        _: &SelectToPreviousSubwordStart,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12859        self.change_selections(Default::default(), window, cx, |s| {
12860            s.move_heads_with(|map, head, _| {
12861                (
12862                    movement::previous_subword_start(map, head),
12863                    SelectionGoal::None,
12864                )
12865            });
12866        })
12867    }
12868
12869    pub fn delete_to_previous_word_start(
12870        &mut self,
12871        action: &DeleteToPreviousWordStart,
12872        window: &mut Window,
12873        cx: &mut Context<Self>,
12874    ) {
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12876        self.transact(window, cx, |this, window, cx| {
12877            this.select_autoclose_pair(window, cx);
12878            this.change_selections(Default::default(), window, cx, |s| {
12879                s.move_with(|map, selection| {
12880                    if selection.is_empty() {
12881                        let cursor = if action.ignore_newlines {
12882                            movement::previous_word_start(map, selection.head())
12883                        } else {
12884                            movement::previous_word_start_or_newline(map, selection.head())
12885                        };
12886                        selection.set_head(cursor, SelectionGoal::None);
12887                    }
12888                });
12889            });
12890            this.insert("", window, cx);
12891        });
12892    }
12893
12894    pub fn delete_to_previous_subword_start(
12895        &mut self,
12896        _: &DeleteToPreviousSubwordStart,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12901        self.transact(window, cx, |this, window, cx| {
12902            this.select_autoclose_pair(window, cx);
12903            this.change_selections(Default::default(), window, cx, |s| {
12904                s.move_with(|map, selection| {
12905                    if selection.is_empty() {
12906                        let cursor = movement::previous_subword_start(map, selection.head());
12907                        selection.set_head(cursor, SelectionGoal::None);
12908                    }
12909                });
12910            });
12911            this.insert("", window, cx);
12912        });
12913    }
12914
12915    pub fn move_to_next_word_end(
12916        &mut self,
12917        _: &MoveToNextWordEnd,
12918        window: &mut Window,
12919        cx: &mut Context<Self>,
12920    ) {
12921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12922        self.change_selections(Default::default(), window, cx, |s| {
12923            s.move_cursors_with(|map, head, _| {
12924                (movement::next_word_end(map, head), SelectionGoal::None)
12925            });
12926        })
12927    }
12928
12929    pub fn move_to_next_subword_end(
12930        &mut self,
12931        _: &MoveToNextSubwordEnd,
12932        window: &mut Window,
12933        cx: &mut Context<Self>,
12934    ) {
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12936        self.change_selections(Default::default(), window, cx, |s| {
12937            s.move_cursors_with(|map, head, _| {
12938                (movement::next_subword_end(map, head), SelectionGoal::None)
12939            });
12940        })
12941    }
12942
12943    pub fn select_to_next_word_end(
12944        &mut self,
12945        _: &SelectToNextWordEnd,
12946        window: &mut Window,
12947        cx: &mut Context<Self>,
12948    ) {
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_heads_with(|map, head, _| {
12952                (movement::next_word_end(map, head), SelectionGoal::None)
12953            });
12954        })
12955    }
12956
12957    pub fn select_to_next_subword_end(
12958        &mut self,
12959        _: &SelectToNextSubwordEnd,
12960        window: &mut Window,
12961        cx: &mut Context<Self>,
12962    ) {
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964        self.change_selections(Default::default(), window, cx, |s| {
12965            s.move_heads_with(|map, head, _| {
12966                (movement::next_subword_end(map, head), SelectionGoal::None)
12967            });
12968        })
12969    }
12970
12971    pub fn delete_to_next_word_end(
12972        &mut self,
12973        action: &DeleteToNextWordEnd,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12978        self.transact(window, cx, |this, window, cx| {
12979            this.change_selections(Default::default(), window, cx, |s| {
12980                s.move_with(|map, selection| {
12981                    if selection.is_empty() {
12982                        let cursor = if action.ignore_newlines {
12983                            movement::next_word_end(map, selection.head())
12984                        } else {
12985                            movement::next_word_end_or_newline(map, selection.head())
12986                        };
12987                        selection.set_head(cursor, SelectionGoal::None);
12988                    }
12989                });
12990            });
12991            this.insert("", window, cx);
12992        });
12993    }
12994
12995    pub fn delete_to_next_subword_end(
12996        &mut self,
12997        _: &DeleteToNextSubwordEnd,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) {
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13002        self.transact(window, cx, |this, window, cx| {
13003            this.change_selections(Default::default(), window, cx, |s| {
13004                s.move_with(|map, selection| {
13005                    if selection.is_empty() {
13006                        let cursor = movement::next_subword_end(map, selection.head());
13007                        selection.set_head(cursor, SelectionGoal::None);
13008                    }
13009                });
13010            });
13011            this.insert("", window, cx);
13012        });
13013    }
13014
13015    pub fn move_to_beginning_of_line(
13016        &mut self,
13017        action: &MoveToBeginningOfLine,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_cursors_with(|map, head, _| {
13024                (
13025                    movement::indented_line_beginning(
13026                        map,
13027                        head,
13028                        action.stop_at_soft_wraps,
13029                        action.stop_at_indent,
13030                    ),
13031                    SelectionGoal::None,
13032                )
13033            });
13034        })
13035    }
13036
13037    pub fn select_to_beginning_of_line(
13038        &mut self,
13039        action: &SelectToBeginningOfLine,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044        self.change_selections(Default::default(), window, cx, |s| {
13045            s.move_heads_with(|map, head, _| {
13046                (
13047                    movement::indented_line_beginning(
13048                        map,
13049                        head,
13050                        action.stop_at_soft_wraps,
13051                        action.stop_at_indent,
13052                    ),
13053                    SelectionGoal::None,
13054                )
13055            });
13056        });
13057    }
13058
13059    pub fn delete_to_beginning_of_line(
13060        &mut self,
13061        action: &DeleteToBeginningOfLine,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13066        self.transact(window, cx, |this, window, cx| {
13067            this.change_selections(Default::default(), window, cx, |s| {
13068                s.move_with(|_, selection| {
13069                    selection.reversed = true;
13070                });
13071            });
13072
13073            this.select_to_beginning_of_line(
13074                &SelectToBeginningOfLine {
13075                    stop_at_soft_wraps: false,
13076                    stop_at_indent: action.stop_at_indent,
13077                },
13078                window,
13079                cx,
13080            );
13081            this.backspace(&Backspace, window, cx);
13082        });
13083    }
13084
13085    pub fn move_to_end_of_line(
13086        &mut self,
13087        action: &MoveToEndOfLine,
13088        window: &mut Window,
13089        cx: &mut Context<Self>,
13090    ) {
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092        self.change_selections(Default::default(), window, cx, |s| {
13093            s.move_cursors_with(|map, head, _| {
13094                (
13095                    movement::line_end(map, head, action.stop_at_soft_wraps),
13096                    SelectionGoal::None,
13097                )
13098            });
13099        })
13100    }
13101
13102    pub fn select_to_end_of_line(
13103        &mut self,
13104        action: &SelectToEndOfLine,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_heads_with(|map, head, _| {
13111                (
13112                    movement::line_end(map, head, action.stop_at_soft_wraps),
13113                    SelectionGoal::None,
13114                )
13115            });
13116        })
13117    }
13118
13119    pub fn delete_to_end_of_line(
13120        &mut self,
13121        _: &DeleteToEndOfLine,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13126        self.transact(window, cx, |this, window, cx| {
13127            this.select_to_end_of_line(
13128                &SelectToEndOfLine {
13129                    stop_at_soft_wraps: false,
13130                },
13131                window,
13132                cx,
13133            );
13134            this.delete(&Delete, window, cx);
13135        });
13136    }
13137
13138    pub fn cut_to_end_of_line(
13139        &mut self,
13140        _: &CutToEndOfLine,
13141        window: &mut Window,
13142        cx: &mut Context<Self>,
13143    ) {
13144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13145        self.transact(window, cx, |this, window, cx| {
13146            this.select_to_end_of_line(
13147                &SelectToEndOfLine {
13148                    stop_at_soft_wraps: false,
13149                },
13150                window,
13151                cx,
13152            );
13153            this.cut(&Cut, window, cx);
13154        });
13155    }
13156
13157    pub fn move_to_start_of_paragraph(
13158        &mut self,
13159        _: &MoveToStartOfParagraph,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) {
13163        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13164            cx.propagate();
13165            return;
13166        }
13167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13168        self.change_selections(Default::default(), window, cx, |s| {
13169            s.move_with(|map, selection| {
13170                selection.collapse_to(
13171                    movement::start_of_paragraph(map, selection.head(), 1),
13172                    SelectionGoal::None,
13173                )
13174            });
13175        })
13176    }
13177
13178    pub fn move_to_end_of_paragraph(
13179        &mut self,
13180        _: &MoveToEndOfParagraph,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13185            cx.propagate();
13186            return;
13187        }
13188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_with(|map, selection| {
13191                selection.collapse_to(
13192                    movement::end_of_paragraph(map, selection.head(), 1),
13193                    SelectionGoal::None,
13194                )
13195            });
13196        })
13197    }
13198
13199    pub fn select_to_start_of_paragraph(
13200        &mut self,
13201        _: &SelectToStartOfParagraph,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13206            cx.propagate();
13207            return;
13208        }
13209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13210        self.change_selections(Default::default(), window, cx, |s| {
13211            s.move_heads_with(|map, head, _| {
13212                (
13213                    movement::start_of_paragraph(map, head, 1),
13214                    SelectionGoal::None,
13215                )
13216            });
13217        })
13218    }
13219
13220    pub fn select_to_end_of_paragraph(
13221        &mut self,
13222        _: &SelectToEndOfParagraph,
13223        window: &mut Window,
13224        cx: &mut Context<Self>,
13225    ) {
13226        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13227            cx.propagate();
13228            return;
13229        }
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_heads_with(|map, head, _| {
13233                (
13234                    movement::end_of_paragraph(map, head, 1),
13235                    SelectionGoal::None,
13236                )
13237            });
13238        })
13239    }
13240
13241    pub fn move_to_start_of_excerpt(
13242        &mut self,
13243        _: &MoveToStartOfExcerpt,
13244        window: &mut Window,
13245        cx: &mut Context<Self>,
13246    ) {
13247        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13248            cx.propagate();
13249            return;
13250        }
13251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13252        self.change_selections(Default::default(), window, cx, |s| {
13253            s.move_with(|map, selection| {
13254                selection.collapse_to(
13255                    movement::start_of_excerpt(
13256                        map,
13257                        selection.head(),
13258                        workspace::searchable::Direction::Prev,
13259                    ),
13260                    SelectionGoal::None,
13261                )
13262            });
13263        })
13264    }
13265
13266    pub fn move_to_start_of_next_excerpt(
13267        &mut self,
13268        _: &MoveToStartOfNextExcerpt,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13273            cx.propagate();
13274            return;
13275        }
13276
13277        self.change_selections(Default::default(), window, cx, |s| {
13278            s.move_with(|map, selection| {
13279                selection.collapse_to(
13280                    movement::start_of_excerpt(
13281                        map,
13282                        selection.head(),
13283                        workspace::searchable::Direction::Next,
13284                    ),
13285                    SelectionGoal::None,
13286                )
13287            });
13288        })
13289    }
13290
13291    pub fn move_to_end_of_excerpt(
13292        &mut self,
13293        _: &MoveToEndOfExcerpt,
13294        window: &mut Window,
13295        cx: &mut Context<Self>,
13296    ) {
13297        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13298            cx.propagate();
13299            return;
13300        }
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13302        self.change_selections(Default::default(), window, cx, |s| {
13303            s.move_with(|map, selection| {
13304                selection.collapse_to(
13305                    movement::end_of_excerpt(
13306                        map,
13307                        selection.head(),
13308                        workspace::searchable::Direction::Next,
13309                    ),
13310                    SelectionGoal::None,
13311                )
13312            });
13313        })
13314    }
13315
13316    pub fn move_to_end_of_previous_excerpt(
13317        &mut self,
13318        _: &MoveToEndOfPreviousExcerpt,
13319        window: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13323            cx.propagate();
13324            return;
13325        }
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327        self.change_selections(Default::default(), window, cx, |s| {
13328            s.move_with(|map, selection| {
13329                selection.collapse_to(
13330                    movement::end_of_excerpt(
13331                        map,
13332                        selection.head(),
13333                        workspace::searchable::Direction::Prev,
13334                    ),
13335                    SelectionGoal::None,
13336                )
13337            });
13338        })
13339    }
13340
13341    pub fn select_to_start_of_excerpt(
13342        &mut self,
13343        _: &SelectToStartOfExcerpt,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13348            cx.propagate();
13349            return;
13350        }
13351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13352        self.change_selections(Default::default(), window, cx, |s| {
13353            s.move_heads_with(|map, head, _| {
13354                (
13355                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13356                    SelectionGoal::None,
13357                )
13358            });
13359        })
13360    }
13361
13362    pub fn select_to_start_of_next_excerpt(
13363        &mut self,
13364        _: &SelectToStartOfNextExcerpt,
13365        window: &mut Window,
13366        cx: &mut Context<Self>,
13367    ) {
13368        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13369            cx.propagate();
13370            return;
13371        }
13372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13373        self.change_selections(Default::default(), window, cx, |s| {
13374            s.move_heads_with(|map, head, _| {
13375                (
13376                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13377                    SelectionGoal::None,
13378                )
13379            });
13380        })
13381    }
13382
13383    pub fn select_to_end_of_excerpt(
13384        &mut self,
13385        _: &SelectToEndOfExcerpt,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13390            cx.propagate();
13391            return;
13392        }
13393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13394        self.change_selections(Default::default(), window, cx, |s| {
13395            s.move_heads_with(|map, head, _| {
13396                (
13397                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13398                    SelectionGoal::None,
13399                )
13400            });
13401        })
13402    }
13403
13404    pub fn select_to_end_of_previous_excerpt(
13405        &mut self,
13406        _: &SelectToEndOfPreviousExcerpt,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13411            cx.propagate();
13412            return;
13413        }
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13415        self.change_selections(Default::default(), window, cx, |s| {
13416            s.move_heads_with(|map, head, _| {
13417                (
13418                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13419                    SelectionGoal::None,
13420                )
13421            });
13422        })
13423    }
13424
13425    pub fn move_to_beginning(
13426        &mut self,
13427        _: &MoveToBeginning,
13428        window: &mut Window,
13429        cx: &mut Context<Self>,
13430    ) {
13431        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13432            cx.propagate();
13433            return;
13434        }
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.select_ranges(vec![0..0]);
13438        });
13439    }
13440
13441    pub fn select_to_beginning(
13442        &mut self,
13443        _: &SelectToBeginning,
13444        window: &mut Window,
13445        cx: &mut Context<Self>,
13446    ) {
13447        let mut selection = self.selections.last::<Point>(cx);
13448        selection.set_head(Point::zero(), SelectionGoal::None);
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.select(vec![selection]);
13452        });
13453    }
13454
13455    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13456        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13457            cx.propagate();
13458            return;
13459        }
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13461        let cursor = self.buffer.read(cx).read(cx).len();
13462        self.change_selections(Default::default(), window, cx, |s| {
13463            s.select_ranges(vec![cursor..cursor])
13464        });
13465    }
13466
13467    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13468        self.nav_history = nav_history;
13469    }
13470
13471    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13472        self.nav_history.as_ref()
13473    }
13474
13475    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13476        self.push_to_nav_history(
13477            self.selections.newest_anchor().head(),
13478            None,
13479            false,
13480            true,
13481            cx,
13482        );
13483    }
13484
13485    fn push_to_nav_history(
13486        &mut self,
13487        cursor_anchor: Anchor,
13488        new_position: Option<Point>,
13489        is_deactivate: bool,
13490        always: bool,
13491        cx: &mut Context<Self>,
13492    ) {
13493        if let Some(nav_history) = self.nav_history.as_mut() {
13494            let buffer = self.buffer.read(cx).read(cx);
13495            let cursor_position = cursor_anchor.to_point(&buffer);
13496            let scroll_state = self.scroll_manager.anchor();
13497            let scroll_top_row = scroll_state.top_row(&buffer);
13498            drop(buffer);
13499
13500            if let Some(new_position) = new_position {
13501                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13502                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13503                    return;
13504                }
13505            }
13506
13507            nav_history.push(
13508                Some(NavigationData {
13509                    cursor_anchor,
13510                    cursor_position,
13511                    scroll_anchor: scroll_state,
13512                    scroll_top_row,
13513                }),
13514                cx,
13515            );
13516            cx.emit(EditorEvent::PushedToNavHistory {
13517                anchor: cursor_anchor,
13518                is_deactivate,
13519            })
13520        }
13521    }
13522
13523    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        let buffer = self.buffer.read(cx).snapshot(cx);
13526        let mut selection = self.selections.first::<usize>(cx);
13527        selection.set_head(buffer.len(), SelectionGoal::None);
13528        self.change_selections(Default::default(), window, cx, |s| {
13529            s.select(vec![selection]);
13530        });
13531    }
13532
13533    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13535        let end = self.buffer.read(cx).read(cx).len();
13536        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13537            s.select_ranges(vec![0..end]);
13538        });
13539    }
13540
13541    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13544        let mut selections = self.selections.all::<Point>(cx);
13545        let max_point = display_map.buffer_snapshot.max_point();
13546        for selection in &mut selections {
13547            let rows = selection.spanned_rows(true, &display_map);
13548            selection.start = Point::new(rows.start.0, 0);
13549            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13550            selection.reversed = false;
13551        }
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.select(selections);
13554        });
13555    }
13556
13557    pub fn split_selection_into_lines(
13558        &mut self,
13559        _: &SplitSelectionIntoLines,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        let selections = self
13564            .selections
13565            .all::<Point>(cx)
13566            .into_iter()
13567            .map(|selection| selection.start..selection.end)
13568            .collect::<Vec<_>>();
13569        self.unfold_ranges(&selections, true, true, cx);
13570
13571        let mut new_selection_ranges = Vec::new();
13572        {
13573            let buffer = self.buffer.read(cx).read(cx);
13574            for selection in selections {
13575                for row in selection.start.row..selection.end.row {
13576                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13577                    new_selection_ranges.push(cursor..cursor);
13578                }
13579
13580                let is_multiline_selection = selection.start.row != selection.end.row;
13581                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13582                // so this action feels more ergonomic when paired with other selection operations
13583                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13584                if !should_skip_last {
13585                    new_selection_ranges.push(selection.end..selection.end);
13586                }
13587            }
13588        }
13589        self.change_selections(Default::default(), window, cx, |s| {
13590            s.select_ranges(new_selection_ranges);
13591        });
13592    }
13593
13594    pub fn add_selection_above(
13595        &mut self,
13596        _: &AddSelectionAbove,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.add_selection(true, window, cx);
13601    }
13602
13603    pub fn add_selection_below(
13604        &mut self,
13605        _: &AddSelectionBelow,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.add_selection(false, window, cx);
13610    }
13611
13612    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13613        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13614
13615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13616        let all_selections = self.selections.all::<Point>(cx);
13617        let text_layout_details = self.text_layout_details(window);
13618
13619        let (mut columnar_selections, new_selections_to_columnarize) = {
13620            if let Some(state) = self.add_selections_state.as_ref() {
13621                let columnar_selection_ids: HashSet<_> = state
13622                    .groups
13623                    .iter()
13624                    .flat_map(|group| group.stack.iter())
13625                    .copied()
13626                    .collect();
13627
13628                all_selections
13629                    .into_iter()
13630                    .partition(|s| columnar_selection_ids.contains(&s.id))
13631            } else {
13632                (Vec::new(), all_selections)
13633            }
13634        };
13635
13636        let mut state = self
13637            .add_selections_state
13638            .take()
13639            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13640
13641        for selection in new_selections_to_columnarize {
13642            let range = selection.display_range(&display_map).sorted();
13643            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13644            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13645            let positions = start_x.min(end_x)..start_x.max(end_x);
13646            let mut stack = Vec::new();
13647            for row in range.start.row().0..=range.end.row().0 {
13648                if let Some(selection) = self.selections.build_columnar_selection(
13649                    &display_map,
13650                    DisplayRow(row),
13651                    &positions,
13652                    selection.reversed,
13653                    &text_layout_details,
13654                ) {
13655                    stack.push(selection.id);
13656                    columnar_selections.push(selection);
13657                }
13658            }
13659            if !stack.is_empty() {
13660                if above {
13661                    stack.reverse();
13662                }
13663                state.groups.push(AddSelectionsGroup { above, stack });
13664            }
13665        }
13666
13667        let mut final_selections = Vec::new();
13668        let end_row = if above {
13669            DisplayRow(0)
13670        } else {
13671            display_map.max_point().row()
13672        };
13673
13674        let mut last_added_item_per_group = HashMap::default();
13675        for group in state.groups.iter_mut() {
13676            if let Some(last_id) = group.stack.last() {
13677                last_added_item_per_group.insert(*last_id, group);
13678            }
13679        }
13680
13681        for selection in columnar_selections {
13682            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13683                if above == group.above {
13684                    let range = selection.display_range(&display_map).sorted();
13685                    debug_assert_eq!(range.start.row(), range.end.row());
13686                    let mut row = range.start.row();
13687                    let positions =
13688                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13689                            px(start)..px(end)
13690                        } else {
13691                            let start_x =
13692                                display_map.x_for_display_point(range.start, &text_layout_details);
13693                            let end_x =
13694                                display_map.x_for_display_point(range.end, &text_layout_details);
13695                            start_x.min(end_x)..start_x.max(end_x)
13696                        };
13697
13698                    let mut maybe_new_selection = None;
13699                    while row != end_row {
13700                        if above {
13701                            row.0 -= 1;
13702                        } else {
13703                            row.0 += 1;
13704                        }
13705                        if let Some(new_selection) = self.selections.build_columnar_selection(
13706                            &display_map,
13707                            row,
13708                            &positions,
13709                            selection.reversed,
13710                            &text_layout_details,
13711                        ) {
13712                            maybe_new_selection = Some(new_selection);
13713                            break;
13714                        }
13715                    }
13716
13717                    if let Some(new_selection) = maybe_new_selection {
13718                        group.stack.push(new_selection.id);
13719                        if above {
13720                            final_selections.push(new_selection);
13721                            final_selections.push(selection);
13722                        } else {
13723                            final_selections.push(selection);
13724                            final_selections.push(new_selection);
13725                        }
13726                    } else {
13727                        final_selections.push(selection);
13728                    }
13729                } else {
13730                    group.stack.pop();
13731                }
13732            } else {
13733                final_selections.push(selection);
13734            }
13735        }
13736
13737        self.change_selections(Default::default(), window, cx, |s| {
13738            s.select(final_selections);
13739        });
13740
13741        let final_selection_ids: HashSet<_> = self
13742            .selections
13743            .all::<Point>(cx)
13744            .iter()
13745            .map(|s| s.id)
13746            .collect();
13747        state.groups.retain_mut(|group| {
13748            // selections might get merged above so we remove invalid items from stacks
13749            group.stack.retain(|id| final_selection_ids.contains(id));
13750
13751            // single selection in stack can be treated as initial state
13752            group.stack.len() > 1
13753        });
13754
13755        if !state.groups.is_empty() {
13756            self.add_selections_state = Some(state);
13757        }
13758    }
13759
13760    fn select_match_ranges(
13761        &mut self,
13762        range: Range<usize>,
13763        reversed: bool,
13764        replace_newest: bool,
13765        auto_scroll: Option<Autoscroll>,
13766        window: &mut Window,
13767        cx: &mut Context<Editor>,
13768    ) {
13769        self.unfold_ranges(
13770            std::slice::from_ref(&range),
13771            false,
13772            auto_scroll.is_some(),
13773            cx,
13774        );
13775        let effects = if let Some(scroll) = auto_scroll {
13776            SelectionEffects::scroll(scroll)
13777        } else {
13778            SelectionEffects::no_scroll()
13779        };
13780        self.change_selections(effects, window, cx, |s| {
13781            if replace_newest {
13782                s.delete(s.newest_anchor().id);
13783            }
13784            if reversed {
13785                s.insert_range(range.end..range.start);
13786            } else {
13787                s.insert_range(range);
13788            }
13789        });
13790    }
13791
13792    pub fn select_next_match_internal(
13793        &mut self,
13794        display_map: &DisplaySnapshot,
13795        replace_newest: bool,
13796        autoscroll: Option<Autoscroll>,
13797        window: &mut Window,
13798        cx: &mut Context<Self>,
13799    ) -> Result<()> {
13800        let buffer = &display_map.buffer_snapshot;
13801        let mut selections = self.selections.all::<usize>(cx);
13802        if let Some(mut select_next_state) = self.select_next_state.take() {
13803            let query = &select_next_state.query;
13804            if !select_next_state.done {
13805                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13806                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13807                let mut next_selected_range = None;
13808
13809                let bytes_after_last_selection =
13810                    buffer.bytes_in_range(last_selection.end..buffer.len());
13811                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13812                let query_matches = query
13813                    .stream_find_iter(bytes_after_last_selection)
13814                    .map(|result| (last_selection.end, result))
13815                    .chain(
13816                        query
13817                            .stream_find_iter(bytes_before_first_selection)
13818                            .map(|result| (0, result)),
13819                    );
13820
13821                for (start_offset, query_match) in query_matches {
13822                    let query_match = query_match.unwrap(); // can only fail due to I/O
13823                    let offset_range =
13824                        start_offset + query_match.start()..start_offset + query_match.end();
13825
13826                    if !select_next_state.wordwise
13827                        || (!buffer.is_inside_word(offset_range.start, false)
13828                            && !buffer.is_inside_word(offset_range.end, false))
13829                    {
13830                        // TODO: This is n^2, because we might check all the selections
13831                        if !selections
13832                            .iter()
13833                            .any(|selection| selection.range().overlaps(&offset_range))
13834                        {
13835                            next_selected_range = Some(offset_range);
13836                            break;
13837                        }
13838                    }
13839                }
13840
13841                if let Some(next_selected_range) = next_selected_range {
13842                    self.select_match_ranges(
13843                        next_selected_range,
13844                        last_selection.reversed,
13845                        replace_newest,
13846                        autoscroll,
13847                        window,
13848                        cx,
13849                    );
13850                } else {
13851                    select_next_state.done = true;
13852                }
13853            }
13854
13855            self.select_next_state = Some(select_next_state);
13856        } else {
13857            let mut only_carets = true;
13858            let mut same_text_selected = true;
13859            let mut selected_text = None;
13860
13861            let mut selections_iter = selections.iter().peekable();
13862            while let Some(selection) = selections_iter.next() {
13863                if selection.start != selection.end {
13864                    only_carets = false;
13865                }
13866
13867                if same_text_selected {
13868                    if selected_text.is_none() {
13869                        selected_text =
13870                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13871                    }
13872
13873                    if let Some(next_selection) = selections_iter.peek() {
13874                        if next_selection.range().len() == selection.range().len() {
13875                            let next_selected_text = buffer
13876                                .text_for_range(next_selection.range())
13877                                .collect::<String>();
13878                            if Some(next_selected_text) != selected_text {
13879                                same_text_selected = false;
13880                                selected_text = None;
13881                            }
13882                        } else {
13883                            same_text_selected = false;
13884                            selected_text = None;
13885                        }
13886                    }
13887                }
13888            }
13889
13890            if only_carets {
13891                for selection in &mut selections {
13892                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13893                    selection.start = word_range.start;
13894                    selection.end = word_range.end;
13895                    selection.goal = SelectionGoal::None;
13896                    selection.reversed = false;
13897                    self.select_match_ranges(
13898                        selection.start..selection.end,
13899                        selection.reversed,
13900                        replace_newest,
13901                        autoscroll,
13902                        window,
13903                        cx,
13904                    );
13905                }
13906
13907                if selections.len() == 1 {
13908                    let selection = selections
13909                        .last()
13910                        .expect("ensured that there's only one selection");
13911                    let query = buffer
13912                        .text_for_range(selection.start..selection.end)
13913                        .collect::<String>();
13914                    let is_empty = query.is_empty();
13915                    let select_state = SelectNextState {
13916                        query: AhoCorasick::new(&[query])?,
13917                        wordwise: true,
13918                        done: is_empty,
13919                    };
13920                    self.select_next_state = Some(select_state);
13921                } else {
13922                    self.select_next_state = None;
13923                }
13924            } else if let Some(selected_text) = selected_text {
13925                self.select_next_state = Some(SelectNextState {
13926                    query: AhoCorasick::new(&[selected_text])?,
13927                    wordwise: false,
13928                    done: false,
13929                });
13930                self.select_next_match_internal(
13931                    display_map,
13932                    replace_newest,
13933                    autoscroll,
13934                    window,
13935                    cx,
13936                )?;
13937            }
13938        }
13939        Ok(())
13940    }
13941
13942    pub fn select_all_matches(
13943        &mut self,
13944        _action: &SelectAllMatches,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) -> Result<()> {
13948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13949
13950        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13951
13952        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13953        let Some(select_next_state) = self.select_next_state.as_mut() else {
13954            return Ok(());
13955        };
13956        if select_next_state.done {
13957            return Ok(());
13958        }
13959
13960        let mut new_selections = Vec::new();
13961
13962        let reversed = self.selections.oldest::<usize>(cx).reversed;
13963        let buffer = &display_map.buffer_snapshot;
13964        let query_matches = select_next_state
13965            .query
13966            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13967
13968        for query_match in query_matches.into_iter() {
13969            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13970            let offset_range = if reversed {
13971                query_match.end()..query_match.start()
13972            } else {
13973                query_match.start()..query_match.end()
13974            };
13975
13976            if !select_next_state.wordwise
13977                || (!buffer.is_inside_word(offset_range.start, false)
13978                    && !buffer.is_inside_word(offset_range.end, false))
13979            {
13980                new_selections.push(offset_range.start..offset_range.end);
13981            }
13982        }
13983
13984        select_next_state.done = true;
13985
13986        if new_selections.is_empty() {
13987            log::error!("bug: new_selections is empty in select_all_matches");
13988            return Ok(());
13989        }
13990
13991        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13992        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13993            selections.select_ranges(new_selections)
13994        });
13995
13996        Ok(())
13997    }
13998
13999    pub fn select_next(
14000        &mut self,
14001        action: &SelectNext,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) -> Result<()> {
14005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14006        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14007        self.select_next_match_internal(
14008            &display_map,
14009            action.replace_newest,
14010            Some(Autoscroll::newest()),
14011            window,
14012            cx,
14013        )?;
14014        Ok(())
14015    }
14016
14017    pub fn select_previous(
14018        &mut self,
14019        action: &SelectPrevious,
14020        window: &mut Window,
14021        cx: &mut Context<Self>,
14022    ) -> Result<()> {
14023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14024        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14025        let buffer = &display_map.buffer_snapshot;
14026        let mut selections = self.selections.all::<usize>(cx);
14027        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14028            let query = &select_prev_state.query;
14029            if !select_prev_state.done {
14030                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14031                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14032                let mut next_selected_range = None;
14033                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14034                let bytes_before_last_selection =
14035                    buffer.reversed_bytes_in_range(0..last_selection.start);
14036                let bytes_after_first_selection =
14037                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14038                let query_matches = query
14039                    .stream_find_iter(bytes_before_last_selection)
14040                    .map(|result| (last_selection.start, result))
14041                    .chain(
14042                        query
14043                            .stream_find_iter(bytes_after_first_selection)
14044                            .map(|result| (buffer.len(), result)),
14045                    );
14046                for (end_offset, query_match) in query_matches {
14047                    let query_match = query_match.unwrap(); // can only fail due to I/O
14048                    let offset_range =
14049                        end_offset - query_match.end()..end_offset - query_match.start();
14050
14051                    if !select_prev_state.wordwise
14052                        || (!buffer.is_inside_word(offset_range.start, false)
14053                            && !buffer.is_inside_word(offset_range.end, false))
14054                    {
14055                        next_selected_range = Some(offset_range);
14056                        break;
14057                    }
14058                }
14059
14060                if let Some(next_selected_range) = next_selected_range {
14061                    self.select_match_ranges(
14062                        next_selected_range,
14063                        last_selection.reversed,
14064                        action.replace_newest,
14065                        Some(Autoscroll::newest()),
14066                        window,
14067                        cx,
14068                    );
14069                } else {
14070                    select_prev_state.done = true;
14071                }
14072            }
14073
14074            self.select_prev_state = Some(select_prev_state);
14075        } else {
14076            let mut only_carets = true;
14077            let mut same_text_selected = true;
14078            let mut selected_text = None;
14079
14080            let mut selections_iter = selections.iter().peekable();
14081            while let Some(selection) = selections_iter.next() {
14082                if selection.start != selection.end {
14083                    only_carets = false;
14084                }
14085
14086                if same_text_selected {
14087                    if selected_text.is_none() {
14088                        selected_text =
14089                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14090                    }
14091
14092                    if let Some(next_selection) = selections_iter.peek() {
14093                        if next_selection.range().len() == selection.range().len() {
14094                            let next_selected_text = buffer
14095                                .text_for_range(next_selection.range())
14096                                .collect::<String>();
14097                            if Some(next_selected_text) != selected_text {
14098                                same_text_selected = false;
14099                                selected_text = None;
14100                            }
14101                        } else {
14102                            same_text_selected = false;
14103                            selected_text = None;
14104                        }
14105                    }
14106                }
14107            }
14108
14109            if only_carets {
14110                for selection in &mut selections {
14111                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14112                    selection.start = word_range.start;
14113                    selection.end = word_range.end;
14114                    selection.goal = SelectionGoal::None;
14115                    selection.reversed = false;
14116                    self.select_match_ranges(
14117                        selection.start..selection.end,
14118                        selection.reversed,
14119                        action.replace_newest,
14120                        Some(Autoscroll::newest()),
14121                        window,
14122                        cx,
14123                    );
14124                }
14125                if selections.len() == 1 {
14126                    let selection = selections
14127                        .last()
14128                        .expect("ensured that there's only one selection");
14129                    let query = buffer
14130                        .text_for_range(selection.start..selection.end)
14131                        .collect::<String>();
14132                    let is_empty = query.is_empty();
14133                    let select_state = SelectNextState {
14134                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14135                        wordwise: true,
14136                        done: is_empty,
14137                    };
14138                    self.select_prev_state = Some(select_state);
14139                } else {
14140                    self.select_prev_state = None;
14141                }
14142            } else if let Some(selected_text) = selected_text {
14143                self.select_prev_state = Some(SelectNextState {
14144                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14145                    wordwise: false,
14146                    done: false,
14147                });
14148                self.select_previous(action, window, cx)?;
14149            }
14150        }
14151        Ok(())
14152    }
14153
14154    pub fn find_next_match(
14155        &mut self,
14156        _: &FindNextMatch,
14157        window: &mut Window,
14158        cx: &mut Context<Self>,
14159    ) -> Result<()> {
14160        let selections = self.selections.disjoint_anchors();
14161        match selections.first() {
14162            Some(first) if selections.len() >= 2 => {
14163                self.change_selections(Default::default(), window, cx, |s| {
14164                    s.select_ranges([first.range()]);
14165                });
14166            }
14167            _ => self.select_next(
14168                &SelectNext {
14169                    replace_newest: true,
14170                },
14171                window,
14172                cx,
14173            )?,
14174        }
14175        Ok(())
14176    }
14177
14178    pub fn find_previous_match(
14179        &mut self,
14180        _: &FindPreviousMatch,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) -> Result<()> {
14184        let selections = self.selections.disjoint_anchors();
14185        match selections.last() {
14186            Some(last) if selections.len() >= 2 => {
14187                self.change_selections(Default::default(), window, cx, |s| {
14188                    s.select_ranges([last.range()]);
14189                });
14190            }
14191            _ => self.select_previous(
14192                &SelectPrevious {
14193                    replace_newest: true,
14194                },
14195                window,
14196                cx,
14197            )?,
14198        }
14199        Ok(())
14200    }
14201
14202    pub fn toggle_comments(
14203        &mut self,
14204        action: &ToggleComments,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) {
14208        if self.read_only(cx) {
14209            return;
14210        }
14211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14212        let text_layout_details = &self.text_layout_details(window);
14213        self.transact(window, cx, |this, window, cx| {
14214            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14215            let mut edits = Vec::new();
14216            let mut selection_edit_ranges = Vec::new();
14217            let mut last_toggled_row = None;
14218            let snapshot = this.buffer.read(cx).read(cx);
14219            let empty_str: Arc<str> = Arc::default();
14220            let mut suffixes_inserted = Vec::new();
14221            let ignore_indent = action.ignore_indent;
14222
14223            fn comment_prefix_range(
14224                snapshot: &MultiBufferSnapshot,
14225                row: MultiBufferRow,
14226                comment_prefix: &str,
14227                comment_prefix_whitespace: &str,
14228                ignore_indent: bool,
14229            ) -> Range<Point> {
14230                let indent_size = if ignore_indent {
14231                    0
14232                } else {
14233                    snapshot.indent_size_for_line(row).len
14234                };
14235
14236                let start = Point::new(row.0, indent_size);
14237
14238                let mut line_bytes = snapshot
14239                    .bytes_in_range(start..snapshot.max_point())
14240                    .flatten()
14241                    .copied();
14242
14243                // If this line currently begins with the line comment prefix, then record
14244                // the range containing the prefix.
14245                if line_bytes
14246                    .by_ref()
14247                    .take(comment_prefix.len())
14248                    .eq(comment_prefix.bytes())
14249                {
14250                    // Include any whitespace that matches the comment prefix.
14251                    let matching_whitespace_len = line_bytes
14252                        .zip(comment_prefix_whitespace.bytes())
14253                        .take_while(|(a, b)| a == b)
14254                        .count() as u32;
14255                    let end = Point::new(
14256                        start.row,
14257                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14258                    );
14259                    start..end
14260                } else {
14261                    start..start
14262                }
14263            }
14264
14265            fn comment_suffix_range(
14266                snapshot: &MultiBufferSnapshot,
14267                row: MultiBufferRow,
14268                comment_suffix: &str,
14269                comment_suffix_has_leading_space: bool,
14270            ) -> Range<Point> {
14271                let end = Point::new(row.0, snapshot.line_len(row));
14272                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14273
14274                let mut line_end_bytes = snapshot
14275                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14276                    .flatten()
14277                    .copied();
14278
14279                let leading_space_len = if suffix_start_column > 0
14280                    && line_end_bytes.next() == Some(b' ')
14281                    && comment_suffix_has_leading_space
14282                {
14283                    1
14284                } else {
14285                    0
14286                };
14287
14288                // If this line currently begins with the line comment prefix, then record
14289                // the range containing the prefix.
14290                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14291                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14292                    start..end
14293                } else {
14294                    end..end
14295                }
14296            }
14297
14298            // TODO: Handle selections that cross excerpts
14299            for selection in &mut selections {
14300                let start_column = snapshot
14301                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14302                    .len;
14303                let language = if let Some(language) =
14304                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14305                {
14306                    language
14307                } else {
14308                    continue;
14309                };
14310
14311                selection_edit_ranges.clear();
14312
14313                // If multiple selections contain a given row, avoid processing that
14314                // row more than once.
14315                let mut start_row = MultiBufferRow(selection.start.row);
14316                if last_toggled_row == Some(start_row) {
14317                    start_row = start_row.next_row();
14318                }
14319                let end_row =
14320                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14321                        MultiBufferRow(selection.end.row - 1)
14322                    } else {
14323                        MultiBufferRow(selection.end.row)
14324                    };
14325                last_toggled_row = Some(end_row);
14326
14327                if start_row > end_row {
14328                    continue;
14329                }
14330
14331                // If the language has line comments, toggle those.
14332                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14333
14334                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14335                if ignore_indent {
14336                    full_comment_prefixes = full_comment_prefixes
14337                        .into_iter()
14338                        .map(|s| Arc::from(s.trim_end()))
14339                        .collect();
14340                }
14341
14342                if !full_comment_prefixes.is_empty() {
14343                    let first_prefix = full_comment_prefixes
14344                        .first()
14345                        .expect("prefixes is non-empty");
14346                    let prefix_trimmed_lengths = full_comment_prefixes
14347                        .iter()
14348                        .map(|p| p.trim_end_matches(' ').len())
14349                        .collect::<SmallVec<[usize; 4]>>();
14350
14351                    let mut all_selection_lines_are_comments = true;
14352
14353                    for row in start_row.0..=end_row.0 {
14354                        let row = MultiBufferRow(row);
14355                        if start_row < end_row && snapshot.is_line_blank(row) {
14356                            continue;
14357                        }
14358
14359                        let prefix_range = full_comment_prefixes
14360                            .iter()
14361                            .zip(prefix_trimmed_lengths.iter().copied())
14362                            .map(|(prefix, trimmed_prefix_len)| {
14363                                comment_prefix_range(
14364                                    snapshot.deref(),
14365                                    row,
14366                                    &prefix[..trimmed_prefix_len],
14367                                    &prefix[trimmed_prefix_len..],
14368                                    ignore_indent,
14369                                )
14370                            })
14371                            .max_by_key(|range| range.end.column - range.start.column)
14372                            .expect("prefixes is non-empty");
14373
14374                        if prefix_range.is_empty() {
14375                            all_selection_lines_are_comments = false;
14376                        }
14377
14378                        selection_edit_ranges.push(prefix_range);
14379                    }
14380
14381                    if all_selection_lines_are_comments {
14382                        edits.extend(
14383                            selection_edit_ranges
14384                                .iter()
14385                                .cloned()
14386                                .map(|range| (range, empty_str.clone())),
14387                        );
14388                    } else {
14389                        let min_column = selection_edit_ranges
14390                            .iter()
14391                            .map(|range| range.start.column)
14392                            .min()
14393                            .unwrap_or(0);
14394                        edits.extend(selection_edit_ranges.iter().map(|range| {
14395                            let position = Point::new(range.start.row, min_column);
14396                            (position..position, first_prefix.clone())
14397                        }));
14398                    }
14399                } else if let Some(BlockCommentConfig {
14400                    start: full_comment_prefix,
14401                    end: comment_suffix,
14402                    ..
14403                }) = language.block_comment()
14404                {
14405                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14406                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14407                    let prefix_range = comment_prefix_range(
14408                        snapshot.deref(),
14409                        start_row,
14410                        comment_prefix,
14411                        comment_prefix_whitespace,
14412                        ignore_indent,
14413                    );
14414                    let suffix_range = comment_suffix_range(
14415                        snapshot.deref(),
14416                        end_row,
14417                        comment_suffix.trim_start_matches(' '),
14418                        comment_suffix.starts_with(' '),
14419                    );
14420
14421                    if prefix_range.is_empty() || suffix_range.is_empty() {
14422                        edits.push((
14423                            prefix_range.start..prefix_range.start,
14424                            full_comment_prefix.clone(),
14425                        ));
14426                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14427                        suffixes_inserted.push((end_row, comment_suffix.len()));
14428                    } else {
14429                        edits.push((prefix_range, empty_str.clone()));
14430                        edits.push((suffix_range, empty_str.clone()));
14431                    }
14432                } else {
14433                    continue;
14434                }
14435            }
14436
14437            drop(snapshot);
14438            this.buffer.update(cx, |buffer, cx| {
14439                buffer.edit(edits, None, cx);
14440            });
14441
14442            // Adjust selections so that they end before any comment suffixes that
14443            // were inserted.
14444            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14445            let mut selections = this.selections.all::<Point>(cx);
14446            let snapshot = this.buffer.read(cx).read(cx);
14447            for selection in &mut selections {
14448                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14449                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14450                        Ordering::Less => {
14451                            suffixes_inserted.next();
14452                            continue;
14453                        }
14454                        Ordering::Greater => break,
14455                        Ordering::Equal => {
14456                            if selection.end.column == snapshot.line_len(row) {
14457                                if selection.is_empty() {
14458                                    selection.start.column -= suffix_len as u32;
14459                                }
14460                                selection.end.column -= suffix_len as u32;
14461                            }
14462                            break;
14463                        }
14464                    }
14465                }
14466            }
14467
14468            drop(snapshot);
14469            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14470
14471            let selections = this.selections.all::<Point>(cx);
14472            let selections_on_single_row = selections.windows(2).all(|selections| {
14473                selections[0].start.row == selections[1].start.row
14474                    && selections[0].end.row == selections[1].end.row
14475                    && selections[0].start.row == selections[0].end.row
14476            });
14477            let selections_selecting = selections
14478                .iter()
14479                .any(|selection| selection.start != selection.end);
14480            let advance_downwards = action.advance_downwards
14481                && selections_on_single_row
14482                && !selections_selecting
14483                && !matches!(this.mode, EditorMode::SingleLine { .. });
14484
14485            if advance_downwards {
14486                let snapshot = this.buffer.read(cx).snapshot(cx);
14487
14488                this.change_selections(Default::default(), window, cx, |s| {
14489                    s.move_cursors_with(|display_snapshot, display_point, _| {
14490                        let mut point = display_point.to_point(display_snapshot);
14491                        point.row += 1;
14492                        point = snapshot.clip_point(point, Bias::Left);
14493                        let display_point = point.to_display_point(display_snapshot);
14494                        let goal = SelectionGoal::HorizontalPosition(
14495                            display_snapshot
14496                                .x_for_display_point(display_point, text_layout_details)
14497                                .into(),
14498                        );
14499                        (display_point, goal)
14500                    })
14501                });
14502            }
14503        });
14504    }
14505
14506    pub fn select_enclosing_symbol(
14507        &mut self,
14508        _: &SelectEnclosingSymbol,
14509        window: &mut Window,
14510        cx: &mut Context<Self>,
14511    ) {
14512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14513
14514        let buffer = self.buffer.read(cx).snapshot(cx);
14515        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14516
14517        fn update_selection(
14518            selection: &Selection<usize>,
14519            buffer_snap: &MultiBufferSnapshot,
14520        ) -> Option<Selection<usize>> {
14521            let cursor = selection.head();
14522            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14523            for symbol in symbols.iter().rev() {
14524                let start = symbol.range.start.to_offset(buffer_snap);
14525                let end = symbol.range.end.to_offset(buffer_snap);
14526                let new_range = start..end;
14527                if start < selection.start || end > selection.end {
14528                    return Some(Selection {
14529                        id: selection.id,
14530                        start: new_range.start,
14531                        end: new_range.end,
14532                        goal: SelectionGoal::None,
14533                        reversed: selection.reversed,
14534                    });
14535                }
14536            }
14537            None
14538        }
14539
14540        let mut selected_larger_symbol = false;
14541        let new_selections = old_selections
14542            .iter()
14543            .map(|selection| match update_selection(selection, &buffer) {
14544                Some(new_selection) => {
14545                    if new_selection.range() != selection.range() {
14546                        selected_larger_symbol = true;
14547                    }
14548                    new_selection
14549                }
14550                None => selection.clone(),
14551            })
14552            .collect::<Vec<_>>();
14553
14554        if selected_larger_symbol {
14555            self.change_selections(Default::default(), window, cx, |s| {
14556                s.select(new_selections);
14557            });
14558        }
14559    }
14560
14561    pub fn select_larger_syntax_node(
14562        &mut self,
14563        _: &SelectLargerSyntaxNode,
14564        window: &mut Window,
14565        cx: &mut Context<Self>,
14566    ) {
14567        let Some(visible_row_count) = self.visible_row_count() else {
14568            return;
14569        };
14570        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14571        if old_selections.is_empty() {
14572            return;
14573        }
14574
14575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14576
14577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14578        let buffer = self.buffer.read(cx).snapshot(cx);
14579
14580        let mut selected_larger_node = false;
14581        let mut new_selections = old_selections
14582            .iter()
14583            .map(|selection| {
14584                let old_range = selection.start..selection.end;
14585
14586                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14587                    // manually select word at selection
14588                    if ["string_content", "inline"].contains(&node.kind()) {
14589                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14590                        // ignore if word is already selected
14591                        if !word_range.is_empty() && old_range != word_range {
14592                            let (last_word_range, _) =
14593                                buffer.surrounding_word(old_range.end, false);
14594                            // only select word if start and end point belongs to same word
14595                            if word_range == last_word_range {
14596                                selected_larger_node = true;
14597                                return Selection {
14598                                    id: selection.id,
14599                                    start: word_range.start,
14600                                    end: word_range.end,
14601                                    goal: SelectionGoal::None,
14602                                    reversed: selection.reversed,
14603                                };
14604                            }
14605                        }
14606                    }
14607                }
14608
14609                let mut new_range = old_range.clone();
14610                while let Some((_node, containing_range)) =
14611                    buffer.syntax_ancestor(new_range.clone())
14612                {
14613                    new_range = match containing_range {
14614                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14615                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14616                    };
14617                    if !display_map.intersects_fold(new_range.start)
14618                        && !display_map.intersects_fold(new_range.end)
14619                    {
14620                        break;
14621                    }
14622                }
14623
14624                selected_larger_node |= new_range != old_range;
14625                Selection {
14626                    id: selection.id,
14627                    start: new_range.start,
14628                    end: new_range.end,
14629                    goal: SelectionGoal::None,
14630                    reversed: selection.reversed,
14631                }
14632            })
14633            .collect::<Vec<_>>();
14634
14635        if !selected_larger_node {
14636            return; // don't put this call in the history
14637        }
14638
14639        // scroll based on transformation done to the last selection created by the user
14640        let (last_old, last_new) = old_selections
14641            .last()
14642            .zip(new_selections.last().cloned())
14643            .expect("old_selections isn't empty");
14644
14645        // revert selection
14646        let is_selection_reversed = {
14647            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14648            new_selections.last_mut().expect("checked above").reversed =
14649                should_newest_selection_be_reversed;
14650            should_newest_selection_be_reversed
14651        };
14652
14653        if selected_larger_node {
14654            self.select_syntax_node_history.disable_clearing = true;
14655            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14656                s.select(new_selections.clone());
14657            });
14658            self.select_syntax_node_history.disable_clearing = false;
14659        }
14660
14661        let start_row = last_new.start.to_display_point(&display_map).row().0;
14662        let end_row = last_new.end.to_display_point(&display_map).row().0;
14663        let selection_height = end_row - start_row + 1;
14664        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14665
14666        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14667        let scroll_behavior = if fits_on_the_screen {
14668            self.request_autoscroll(Autoscroll::fit(), cx);
14669            SelectSyntaxNodeScrollBehavior::FitSelection
14670        } else if is_selection_reversed {
14671            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14672            SelectSyntaxNodeScrollBehavior::CursorTop
14673        } else {
14674            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14675            SelectSyntaxNodeScrollBehavior::CursorBottom
14676        };
14677
14678        self.select_syntax_node_history.push((
14679            old_selections,
14680            scroll_behavior,
14681            is_selection_reversed,
14682        ));
14683    }
14684
14685    pub fn select_smaller_syntax_node(
14686        &mut self,
14687        _: &SelectSmallerSyntaxNode,
14688        window: &mut Window,
14689        cx: &mut Context<Self>,
14690    ) {
14691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14692
14693        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14694            self.select_syntax_node_history.pop()
14695        {
14696            if let Some(selection) = selections.last_mut() {
14697                selection.reversed = is_selection_reversed;
14698            }
14699
14700            self.select_syntax_node_history.disable_clearing = true;
14701            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14702                s.select(selections.to_vec());
14703            });
14704            self.select_syntax_node_history.disable_clearing = false;
14705
14706            match scroll_behavior {
14707                SelectSyntaxNodeScrollBehavior::CursorTop => {
14708                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14709                }
14710                SelectSyntaxNodeScrollBehavior::FitSelection => {
14711                    self.request_autoscroll(Autoscroll::fit(), cx);
14712                }
14713                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14714                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14715                }
14716            }
14717        }
14718    }
14719
14720    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14721        if !EditorSettings::get_global(cx).gutter.runnables {
14722            self.clear_tasks();
14723            return Task::ready(());
14724        }
14725        let project = self.project.as_ref().map(Entity::downgrade);
14726        let task_sources = self.lsp_task_sources(cx);
14727        let multi_buffer = self.buffer.downgrade();
14728        cx.spawn_in(window, async move |editor, cx| {
14729            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14730            let Some(project) = project.and_then(|p| p.upgrade()) else {
14731                return;
14732            };
14733            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14734                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14735            }) else {
14736                return;
14737            };
14738
14739            let hide_runnables = project
14740                .update(cx, |project, cx| {
14741                    // Do not display any test indicators in non-dev server remote projects.
14742                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14743                })
14744                .unwrap_or(true);
14745            if hide_runnables {
14746                return;
14747            }
14748            let new_rows =
14749                cx.background_spawn({
14750                    let snapshot = display_snapshot.clone();
14751                    async move {
14752                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14753                    }
14754                })
14755                    .await;
14756            let Ok(lsp_tasks) =
14757                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14758            else {
14759                return;
14760            };
14761            let lsp_tasks = lsp_tasks.await;
14762
14763            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14764                lsp_tasks
14765                    .into_iter()
14766                    .flat_map(|(kind, tasks)| {
14767                        tasks.into_iter().filter_map(move |(location, task)| {
14768                            Some((kind.clone(), location?, task))
14769                        })
14770                    })
14771                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14772                        let buffer = location.target.buffer;
14773                        let buffer_snapshot = buffer.read(cx).snapshot();
14774                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14775                            |(excerpt_id, snapshot, _)| {
14776                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14777                                    display_snapshot
14778                                        .buffer_snapshot
14779                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14780                                } else {
14781                                    None
14782                                }
14783                            },
14784                        );
14785                        if let Some(offset) = offset {
14786                            let task_buffer_range =
14787                                location.target.range.to_point(&buffer_snapshot);
14788                            let context_buffer_range =
14789                                task_buffer_range.to_offset(&buffer_snapshot);
14790                            let context_range = BufferOffset(context_buffer_range.start)
14791                                ..BufferOffset(context_buffer_range.end);
14792
14793                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14794                                .or_insert_with(|| RunnableTasks {
14795                                    templates: Vec::new(),
14796                                    offset,
14797                                    column: task_buffer_range.start.column,
14798                                    extra_variables: HashMap::default(),
14799                                    context_range,
14800                                })
14801                                .templates
14802                                .push((kind, task.original_task().clone()));
14803                        }
14804
14805                        acc
14806                    })
14807            }) else {
14808                return;
14809            };
14810
14811            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14812                buffer.language_settings(cx).tasks.prefer_lsp
14813            }) else {
14814                return;
14815            };
14816
14817            let rows = Self::runnable_rows(
14818                project,
14819                display_snapshot,
14820                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14821                new_rows,
14822                cx.clone(),
14823            )
14824            .await;
14825            editor
14826                .update(cx, |editor, _| {
14827                    editor.clear_tasks();
14828                    for (key, mut value) in rows {
14829                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14830                            value.templates.extend(lsp_tasks.templates);
14831                        }
14832
14833                        editor.insert_tasks(key, value);
14834                    }
14835                    for (key, value) in lsp_tasks_by_rows {
14836                        editor.insert_tasks(key, value);
14837                    }
14838                })
14839                .ok();
14840        })
14841    }
14842    fn fetch_runnable_ranges(
14843        snapshot: &DisplaySnapshot,
14844        range: Range<Anchor>,
14845    ) -> Vec<language::RunnableRange> {
14846        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14847    }
14848
14849    fn runnable_rows(
14850        project: Entity<Project>,
14851        snapshot: DisplaySnapshot,
14852        prefer_lsp: bool,
14853        runnable_ranges: Vec<RunnableRange>,
14854        cx: AsyncWindowContext,
14855    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14856        cx.spawn(async move |cx| {
14857            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14858            for mut runnable in runnable_ranges {
14859                let Some(tasks) = cx
14860                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14861                    .ok()
14862                else {
14863                    continue;
14864                };
14865                let mut tasks = tasks.await;
14866
14867                if prefer_lsp {
14868                    tasks.retain(|(task_kind, _)| {
14869                        !matches!(task_kind, TaskSourceKind::Language { .. })
14870                    });
14871                }
14872                if tasks.is_empty() {
14873                    continue;
14874                }
14875
14876                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14877                let Some(row) = snapshot
14878                    .buffer_snapshot
14879                    .buffer_line_for_row(MultiBufferRow(point.row))
14880                    .map(|(_, range)| range.start.row)
14881                else {
14882                    continue;
14883                };
14884
14885                let context_range =
14886                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14887                runnable_rows.push((
14888                    (runnable.buffer_id, row),
14889                    RunnableTasks {
14890                        templates: tasks,
14891                        offset: snapshot
14892                            .buffer_snapshot
14893                            .anchor_before(runnable.run_range.start),
14894                        context_range,
14895                        column: point.column,
14896                        extra_variables: runnable.extra_captures,
14897                    },
14898                ));
14899            }
14900            runnable_rows
14901        })
14902    }
14903
14904    fn templates_with_tags(
14905        project: &Entity<Project>,
14906        runnable: &mut Runnable,
14907        cx: &mut App,
14908    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14909        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14910            let (worktree_id, file) = project
14911                .buffer_for_id(runnable.buffer, cx)
14912                .and_then(|buffer| buffer.read(cx).file())
14913                .map(|file| (file.worktree_id(cx), file.clone()))
14914                .unzip();
14915
14916            (
14917                project.task_store().read(cx).task_inventory().cloned(),
14918                worktree_id,
14919                file,
14920            )
14921        });
14922
14923        let tags = mem::take(&mut runnable.tags);
14924        let language = runnable.language.clone();
14925        cx.spawn(async move |cx| {
14926            let mut templates_with_tags = Vec::new();
14927            if let Some(inventory) = inventory {
14928                for RunnableTag(tag) in tags {
14929                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14930                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14931                    }) else {
14932                        return templates_with_tags;
14933                    };
14934                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14935                        move |(_, template)| {
14936                            template.tags.iter().any(|source_tag| source_tag == &tag)
14937                        },
14938                    ));
14939                }
14940            }
14941            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14942
14943            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14944                // Strongest source wins; if we have worktree tag binding, prefer that to
14945                // global and language bindings;
14946                // if we have a global binding, prefer that to language binding.
14947                let first_mismatch = templates_with_tags
14948                    .iter()
14949                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14950                if let Some(index) = first_mismatch {
14951                    templates_with_tags.truncate(index);
14952                }
14953            }
14954
14955            templates_with_tags
14956        })
14957    }
14958
14959    pub fn move_to_enclosing_bracket(
14960        &mut self,
14961        _: &MoveToEnclosingBracket,
14962        window: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) {
14965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14966        self.change_selections(Default::default(), window, cx, |s| {
14967            s.move_offsets_with(|snapshot, selection| {
14968                let Some(enclosing_bracket_ranges) =
14969                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14970                else {
14971                    return;
14972                };
14973
14974                let mut best_length = usize::MAX;
14975                let mut best_inside = false;
14976                let mut best_in_bracket_range = false;
14977                let mut best_destination = None;
14978                for (open, close) in enclosing_bracket_ranges {
14979                    let close = close.to_inclusive();
14980                    let length = close.end() - open.start;
14981                    let inside = selection.start >= open.end && selection.end <= *close.start();
14982                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14983                        || close.contains(&selection.head());
14984
14985                    // If best is next to a bracket and current isn't, skip
14986                    if !in_bracket_range && best_in_bracket_range {
14987                        continue;
14988                    }
14989
14990                    // Prefer smaller lengths unless best is inside and current isn't
14991                    if length > best_length && (best_inside || !inside) {
14992                        continue;
14993                    }
14994
14995                    best_length = length;
14996                    best_inside = inside;
14997                    best_in_bracket_range = in_bracket_range;
14998                    best_destination = Some(
14999                        if close.contains(&selection.start) && close.contains(&selection.end) {
15000                            if inside { open.end } else { open.start }
15001                        } else if inside {
15002                            *close.start()
15003                        } else {
15004                            *close.end()
15005                        },
15006                    );
15007                }
15008
15009                if let Some(destination) = best_destination {
15010                    selection.collapse_to(destination, SelectionGoal::None);
15011                }
15012            })
15013        });
15014    }
15015
15016    pub fn undo_selection(
15017        &mut self,
15018        _: &UndoSelection,
15019        window: &mut Window,
15020        cx: &mut Context<Self>,
15021    ) {
15022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15023        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15024            self.selection_history.mode = SelectionHistoryMode::Undoing;
15025            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15026                this.end_selection(window, cx);
15027                this.change_selections(
15028                    SelectionEffects::scroll(Autoscroll::newest()),
15029                    window,
15030                    cx,
15031                    |s| s.select_anchors(entry.selections.to_vec()),
15032                );
15033            });
15034            self.selection_history.mode = SelectionHistoryMode::Normal;
15035
15036            self.select_next_state = entry.select_next_state;
15037            self.select_prev_state = entry.select_prev_state;
15038            self.add_selections_state = entry.add_selections_state;
15039        }
15040    }
15041
15042    pub fn redo_selection(
15043        &mut self,
15044        _: &RedoSelection,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) {
15048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15049        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15050            self.selection_history.mode = SelectionHistoryMode::Redoing;
15051            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15052                this.end_selection(window, cx);
15053                this.change_selections(
15054                    SelectionEffects::scroll(Autoscroll::newest()),
15055                    window,
15056                    cx,
15057                    |s| s.select_anchors(entry.selections.to_vec()),
15058                );
15059            });
15060            self.selection_history.mode = SelectionHistoryMode::Normal;
15061
15062            self.select_next_state = entry.select_next_state;
15063            self.select_prev_state = entry.select_prev_state;
15064            self.add_selections_state = entry.add_selections_state;
15065        }
15066    }
15067
15068    pub fn expand_excerpts(
15069        &mut self,
15070        action: &ExpandExcerpts,
15071        _: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15075    }
15076
15077    pub fn expand_excerpts_down(
15078        &mut self,
15079        action: &ExpandExcerptsDown,
15080        _: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15084    }
15085
15086    pub fn expand_excerpts_up(
15087        &mut self,
15088        action: &ExpandExcerptsUp,
15089        _: &mut Window,
15090        cx: &mut Context<Self>,
15091    ) {
15092        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15093    }
15094
15095    pub fn expand_excerpts_for_direction(
15096        &mut self,
15097        lines: u32,
15098        direction: ExpandExcerptDirection,
15099
15100        cx: &mut Context<Self>,
15101    ) {
15102        let selections = self.selections.disjoint_anchors();
15103
15104        let lines = if lines == 0 {
15105            EditorSettings::get_global(cx).expand_excerpt_lines
15106        } else {
15107            lines
15108        };
15109
15110        self.buffer.update(cx, |buffer, cx| {
15111            let snapshot = buffer.snapshot(cx);
15112            let mut excerpt_ids = selections
15113                .iter()
15114                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15115                .collect::<Vec<_>>();
15116            excerpt_ids.sort();
15117            excerpt_ids.dedup();
15118            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15119        })
15120    }
15121
15122    pub fn expand_excerpt(
15123        &mut self,
15124        excerpt: ExcerptId,
15125        direction: ExpandExcerptDirection,
15126        window: &mut Window,
15127        cx: &mut Context<Self>,
15128    ) {
15129        let current_scroll_position = self.scroll_position(cx);
15130        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15131        let mut should_scroll_up = false;
15132
15133        if direction == ExpandExcerptDirection::Down {
15134            let multi_buffer = self.buffer.read(cx);
15135            let snapshot = multi_buffer.snapshot(cx);
15136            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15137                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15138                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15139                        let buffer_snapshot = buffer.read(cx).snapshot();
15140                        let excerpt_end_row =
15141                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15142                        let last_row = buffer_snapshot.max_point().row;
15143                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15144                        should_scroll_up = lines_below >= lines_to_expand;
15145                    }
15146                }
15147            }
15148        }
15149
15150        self.buffer.update(cx, |buffer, cx| {
15151            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15152        });
15153
15154        if should_scroll_up {
15155            let new_scroll_position =
15156                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15157            self.set_scroll_position(new_scroll_position, window, cx);
15158        }
15159    }
15160
15161    pub fn go_to_singleton_buffer_point(
15162        &mut self,
15163        point: Point,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) {
15167        self.go_to_singleton_buffer_range(point..point, window, cx);
15168    }
15169
15170    pub fn go_to_singleton_buffer_range(
15171        &mut self,
15172        range: Range<Point>,
15173        window: &mut Window,
15174        cx: &mut Context<Self>,
15175    ) {
15176        let multibuffer = self.buffer().read(cx);
15177        let Some(buffer) = multibuffer.as_singleton() else {
15178            return;
15179        };
15180        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15181            return;
15182        };
15183        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15184            return;
15185        };
15186        self.change_selections(
15187            SelectionEffects::default().nav_history(true),
15188            window,
15189            cx,
15190            |s| s.select_anchor_ranges([start..end]),
15191        );
15192    }
15193
15194    pub fn go_to_diagnostic(
15195        &mut self,
15196        action: &GoToDiagnostic,
15197        window: &mut Window,
15198        cx: &mut Context<Self>,
15199    ) {
15200        if !self.diagnostics_enabled() {
15201            return;
15202        }
15203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15204        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15205    }
15206
15207    pub fn go_to_prev_diagnostic(
15208        &mut self,
15209        action: &GoToPreviousDiagnostic,
15210        window: &mut Window,
15211        cx: &mut Context<Self>,
15212    ) {
15213        if !self.diagnostics_enabled() {
15214            return;
15215        }
15216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15217        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15218    }
15219
15220    pub fn go_to_diagnostic_impl(
15221        &mut self,
15222        direction: Direction,
15223        severity: GoToDiagnosticSeverityFilter,
15224        window: &mut Window,
15225        cx: &mut Context<Self>,
15226    ) {
15227        let buffer = self.buffer.read(cx).snapshot(cx);
15228        let selection = self.selections.newest::<usize>(cx);
15229
15230        let mut active_group_id = None;
15231        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15232            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15233                active_group_id = Some(active_group.group_id);
15234            }
15235        }
15236
15237        fn filtered(
15238            snapshot: EditorSnapshot,
15239            severity: GoToDiagnosticSeverityFilter,
15240            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15241        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15242            diagnostics
15243                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15244                .filter(|entry| entry.range.start != entry.range.end)
15245                .filter(|entry| !entry.diagnostic.is_unnecessary)
15246                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15247        }
15248
15249        let snapshot = self.snapshot(window, cx);
15250        let before = filtered(
15251            snapshot.clone(),
15252            severity,
15253            buffer
15254                .diagnostics_in_range(0..selection.start)
15255                .filter(|entry| entry.range.start <= selection.start),
15256        );
15257        let after = filtered(
15258            snapshot,
15259            severity,
15260            buffer
15261                .diagnostics_in_range(selection.start..buffer.len())
15262                .filter(|entry| entry.range.start >= selection.start),
15263        );
15264
15265        let mut found: Option<DiagnosticEntry<usize>> = None;
15266        if direction == Direction::Prev {
15267            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15268            {
15269                for diagnostic in prev_diagnostics.into_iter().rev() {
15270                    if diagnostic.range.start != selection.start
15271                        || active_group_id
15272                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15273                    {
15274                        found = Some(diagnostic);
15275                        break 'outer;
15276                    }
15277                }
15278            }
15279        } else {
15280            for diagnostic in after.chain(before) {
15281                if diagnostic.range.start != selection.start
15282                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15283                {
15284                    found = Some(diagnostic);
15285                    break;
15286                }
15287            }
15288        }
15289        let Some(next_diagnostic) = found else {
15290            return;
15291        };
15292
15293        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15294            return;
15295        };
15296        self.change_selections(Default::default(), window, cx, |s| {
15297            s.select_ranges(vec![
15298                next_diagnostic.range.start..next_diagnostic.range.start,
15299            ])
15300        });
15301        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15302        self.refresh_inline_completion(false, true, window, cx);
15303    }
15304
15305    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15307        let snapshot = self.snapshot(window, cx);
15308        let selection = self.selections.newest::<Point>(cx);
15309        self.go_to_hunk_before_or_after_position(
15310            &snapshot,
15311            selection.head(),
15312            Direction::Next,
15313            window,
15314            cx,
15315        );
15316    }
15317
15318    pub fn go_to_hunk_before_or_after_position(
15319        &mut self,
15320        snapshot: &EditorSnapshot,
15321        position: Point,
15322        direction: Direction,
15323        window: &mut Window,
15324        cx: &mut Context<Editor>,
15325    ) {
15326        let row = if direction == Direction::Next {
15327            self.hunk_after_position(snapshot, position)
15328                .map(|hunk| hunk.row_range.start)
15329        } else {
15330            self.hunk_before_position(snapshot, position)
15331        };
15332
15333        if let Some(row) = row {
15334            let destination = Point::new(row.0, 0);
15335            let autoscroll = Autoscroll::center();
15336
15337            self.unfold_ranges(&[destination..destination], false, false, cx);
15338            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15339                s.select_ranges([destination..destination]);
15340            });
15341        }
15342    }
15343
15344    fn hunk_after_position(
15345        &mut self,
15346        snapshot: &EditorSnapshot,
15347        position: Point,
15348    ) -> Option<MultiBufferDiffHunk> {
15349        snapshot
15350            .buffer_snapshot
15351            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15352            .find(|hunk| hunk.row_range.start.0 > position.row)
15353            .or_else(|| {
15354                snapshot
15355                    .buffer_snapshot
15356                    .diff_hunks_in_range(Point::zero()..position)
15357                    .find(|hunk| hunk.row_range.end.0 < position.row)
15358            })
15359    }
15360
15361    fn go_to_prev_hunk(
15362        &mut self,
15363        _: &GoToPreviousHunk,
15364        window: &mut Window,
15365        cx: &mut Context<Self>,
15366    ) {
15367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15368        let snapshot = self.snapshot(window, cx);
15369        let selection = self.selections.newest::<Point>(cx);
15370        self.go_to_hunk_before_or_after_position(
15371            &snapshot,
15372            selection.head(),
15373            Direction::Prev,
15374            window,
15375            cx,
15376        );
15377    }
15378
15379    fn hunk_before_position(
15380        &mut self,
15381        snapshot: &EditorSnapshot,
15382        position: Point,
15383    ) -> Option<MultiBufferRow> {
15384        snapshot
15385            .buffer_snapshot
15386            .diff_hunk_before(position)
15387            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15388    }
15389
15390    fn go_to_next_change(
15391        &mut self,
15392        _: &GoToNextChange,
15393        window: &mut Window,
15394        cx: &mut Context<Self>,
15395    ) {
15396        if let Some(selections) = self
15397            .change_list
15398            .next_change(1, Direction::Next)
15399            .map(|s| s.to_vec())
15400        {
15401            self.change_selections(Default::default(), window, cx, |s| {
15402                let map = s.display_map();
15403                s.select_display_ranges(selections.iter().map(|a| {
15404                    let point = a.to_display_point(&map);
15405                    point..point
15406                }))
15407            })
15408        }
15409    }
15410
15411    fn go_to_previous_change(
15412        &mut self,
15413        _: &GoToPreviousChange,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) {
15417        if let Some(selections) = self
15418            .change_list
15419            .next_change(1, Direction::Prev)
15420            .map(|s| s.to_vec())
15421        {
15422            self.change_selections(Default::default(), window, cx, |s| {
15423                let map = s.display_map();
15424                s.select_display_ranges(selections.iter().map(|a| {
15425                    let point = a.to_display_point(&map);
15426                    point..point
15427                }))
15428            })
15429        }
15430    }
15431
15432    fn go_to_line<T: 'static>(
15433        &mut self,
15434        position: Anchor,
15435        highlight_color: Option<Hsla>,
15436        window: &mut Window,
15437        cx: &mut Context<Self>,
15438    ) {
15439        let snapshot = self.snapshot(window, cx).display_snapshot;
15440        let position = position.to_point(&snapshot.buffer_snapshot);
15441        let start = snapshot
15442            .buffer_snapshot
15443            .clip_point(Point::new(position.row, 0), Bias::Left);
15444        let end = start + Point::new(1, 0);
15445        let start = snapshot.buffer_snapshot.anchor_before(start);
15446        let end = snapshot.buffer_snapshot.anchor_before(end);
15447
15448        self.highlight_rows::<T>(
15449            start..end,
15450            highlight_color
15451                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15452            Default::default(),
15453            cx,
15454        );
15455
15456        if self.buffer.read(cx).is_singleton() {
15457            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15458        }
15459    }
15460
15461    pub fn go_to_definition(
15462        &mut self,
15463        _: &GoToDefinition,
15464        window: &mut Window,
15465        cx: &mut Context<Self>,
15466    ) -> Task<Result<Navigated>> {
15467        let definition =
15468            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15469        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15470        cx.spawn_in(window, async move |editor, cx| {
15471            if definition.await? == Navigated::Yes {
15472                return Ok(Navigated::Yes);
15473            }
15474            match fallback_strategy {
15475                GoToDefinitionFallback::None => Ok(Navigated::No),
15476                GoToDefinitionFallback::FindAllReferences => {
15477                    match editor.update_in(cx, |editor, window, cx| {
15478                        editor.find_all_references(&FindAllReferences, window, cx)
15479                    })? {
15480                        Some(references) => references.await,
15481                        None => Ok(Navigated::No),
15482                    }
15483                }
15484            }
15485        })
15486    }
15487
15488    pub fn go_to_declaration(
15489        &mut self,
15490        _: &GoToDeclaration,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) -> Task<Result<Navigated>> {
15494        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15495    }
15496
15497    pub fn go_to_declaration_split(
15498        &mut self,
15499        _: &GoToDeclaration,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) -> Task<Result<Navigated>> {
15503        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15504    }
15505
15506    pub fn go_to_implementation(
15507        &mut self,
15508        _: &GoToImplementation,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) -> Task<Result<Navigated>> {
15512        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15513    }
15514
15515    pub fn go_to_implementation_split(
15516        &mut self,
15517        _: &GoToImplementationSplit,
15518        window: &mut Window,
15519        cx: &mut Context<Self>,
15520    ) -> Task<Result<Navigated>> {
15521        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15522    }
15523
15524    pub fn go_to_type_definition(
15525        &mut self,
15526        _: &GoToTypeDefinition,
15527        window: &mut Window,
15528        cx: &mut Context<Self>,
15529    ) -> Task<Result<Navigated>> {
15530        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15531    }
15532
15533    pub fn go_to_definition_split(
15534        &mut self,
15535        _: &GoToDefinitionSplit,
15536        window: &mut Window,
15537        cx: &mut Context<Self>,
15538    ) -> Task<Result<Navigated>> {
15539        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15540    }
15541
15542    pub fn go_to_type_definition_split(
15543        &mut self,
15544        _: &GoToTypeDefinitionSplit,
15545        window: &mut Window,
15546        cx: &mut Context<Self>,
15547    ) -> Task<Result<Navigated>> {
15548        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15549    }
15550
15551    fn go_to_definition_of_kind(
15552        &mut self,
15553        kind: GotoDefinitionKind,
15554        split: bool,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) -> Task<Result<Navigated>> {
15558        let Some(provider) = self.semantics_provider.clone() else {
15559            return Task::ready(Ok(Navigated::No));
15560        };
15561        let head = self.selections.newest::<usize>(cx).head();
15562        let buffer = self.buffer.read(cx);
15563        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15564            text_anchor
15565        } else {
15566            return Task::ready(Ok(Navigated::No));
15567        };
15568
15569        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15570            return Task::ready(Ok(Navigated::No));
15571        };
15572
15573        cx.spawn_in(window, async move |editor, cx| {
15574            let definitions = definitions.await?;
15575            let navigated = editor
15576                .update_in(cx, |editor, window, cx| {
15577                    editor.navigate_to_hover_links(
15578                        Some(kind),
15579                        definitions
15580                            .into_iter()
15581                            .filter(|location| {
15582                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15583                            })
15584                            .map(HoverLink::Text)
15585                            .collect::<Vec<_>>(),
15586                        split,
15587                        window,
15588                        cx,
15589                    )
15590                })?
15591                .await?;
15592            anyhow::Ok(navigated)
15593        })
15594    }
15595
15596    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15597        let selection = self.selections.newest_anchor();
15598        let head = selection.head();
15599        let tail = selection.tail();
15600
15601        let Some((buffer, start_position)) =
15602            self.buffer.read(cx).text_anchor_for_position(head, cx)
15603        else {
15604            return;
15605        };
15606
15607        let end_position = if head != tail {
15608            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15609                return;
15610            };
15611            Some(pos)
15612        } else {
15613            None
15614        };
15615
15616        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15617            let url = if let Some(end_pos) = end_position {
15618                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15619            } else {
15620                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15621            };
15622
15623            if let Some(url) = url {
15624                editor.update(cx, |_, cx| {
15625                    cx.open_url(&url);
15626                })
15627            } else {
15628                Ok(())
15629            }
15630        });
15631
15632        url_finder.detach();
15633    }
15634
15635    pub fn open_selected_filename(
15636        &mut self,
15637        _: &OpenSelectedFilename,
15638        window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) {
15641        let Some(workspace) = self.workspace() else {
15642            return;
15643        };
15644
15645        let position = self.selections.newest_anchor().head();
15646
15647        let Some((buffer, buffer_position)) =
15648            self.buffer.read(cx).text_anchor_for_position(position, cx)
15649        else {
15650            return;
15651        };
15652
15653        let project = self.project.clone();
15654
15655        cx.spawn_in(window, async move |_, cx| {
15656            let result = find_file(&buffer, project, buffer_position, cx).await;
15657
15658            if let Some((_, path)) = result {
15659                workspace
15660                    .update_in(cx, |workspace, window, cx| {
15661                        workspace.open_resolved_path(path, window, cx)
15662                    })?
15663                    .await?;
15664            }
15665            anyhow::Ok(())
15666        })
15667        .detach();
15668    }
15669
15670    pub(crate) fn navigate_to_hover_links(
15671        &mut self,
15672        kind: Option<GotoDefinitionKind>,
15673        mut definitions: Vec<HoverLink>,
15674        split: bool,
15675        window: &mut Window,
15676        cx: &mut Context<Editor>,
15677    ) -> Task<Result<Navigated>> {
15678        // If there is one definition, just open it directly
15679        if definitions.len() == 1 {
15680            let definition = definitions.pop().unwrap();
15681
15682            enum TargetTaskResult {
15683                Location(Option<Location>),
15684                AlreadyNavigated,
15685            }
15686
15687            let target_task = match definition {
15688                HoverLink::Text(link) => {
15689                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15690                }
15691                HoverLink::InlayHint(lsp_location, server_id) => {
15692                    let computation =
15693                        self.compute_target_location(lsp_location, server_id, window, cx);
15694                    cx.background_spawn(async move {
15695                        let location = computation.await?;
15696                        Ok(TargetTaskResult::Location(location))
15697                    })
15698                }
15699                HoverLink::Url(url) => {
15700                    cx.open_url(&url);
15701                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15702                }
15703                HoverLink::File(path) => {
15704                    if let Some(workspace) = self.workspace() {
15705                        cx.spawn_in(window, async move |_, cx| {
15706                            workspace
15707                                .update_in(cx, |workspace, window, cx| {
15708                                    workspace.open_resolved_path(path, window, cx)
15709                                })?
15710                                .await
15711                                .map(|_| TargetTaskResult::AlreadyNavigated)
15712                        })
15713                    } else {
15714                        Task::ready(Ok(TargetTaskResult::Location(None)))
15715                    }
15716                }
15717            };
15718            cx.spawn_in(window, async move |editor, cx| {
15719                let target = match target_task.await.context("target resolution task")? {
15720                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15721                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15722                    TargetTaskResult::Location(Some(target)) => target,
15723                };
15724
15725                editor.update_in(cx, |editor, window, cx| {
15726                    let Some(workspace) = editor.workspace() else {
15727                        return Navigated::No;
15728                    };
15729                    let pane = workspace.read(cx).active_pane().clone();
15730
15731                    let range = target.range.to_point(target.buffer.read(cx));
15732                    let range = editor.range_for_match(&range);
15733                    let range = collapse_multiline_range(range);
15734
15735                    if !split
15736                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15737                    {
15738                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15739                    } else {
15740                        window.defer(cx, move |window, cx| {
15741                            let target_editor: Entity<Self> =
15742                                workspace.update(cx, |workspace, cx| {
15743                                    let pane = if split {
15744                                        workspace.adjacent_pane(window, cx)
15745                                    } else {
15746                                        workspace.active_pane().clone()
15747                                    };
15748
15749                                    workspace.open_project_item(
15750                                        pane,
15751                                        target.buffer.clone(),
15752                                        true,
15753                                        true,
15754                                        window,
15755                                        cx,
15756                                    )
15757                                });
15758                            target_editor.update(cx, |target_editor, cx| {
15759                                // When selecting a definition in a different buffer, disable the nav history
15760                                // to avoid creating a history entry at the previous cursor location.
15761                                pane.update(cx, |pane, _| pane.disable_history());
15762                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15763                                pane.update(cx, |pane, _| pane.enable_history());
15764                            });
15765                        });
15766                    }
15767                    Navigated::Yes
15768                })
15769            })
15770        } else if !definitions.is_empty() {
15771            cx.spawn_in(window, async move |editor, cx| {
15772                let (title, location_tasks, workspace) = editor
15773                    .update_in(cx, |editor, window, cx| {
15774                        let tab_kind = match kind {
15775                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15776                            _ => "Definitions",
15777                        };
15778                        let title = definitions
15779                            .iter()
15780                            .find_map(|definition| match definition {
15781                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15782                                    let buffer = origin.buffer.read(cx);
15783                                    format!(
15784                                        "{} for {}",
15785                                        tab_kind,
15786                                        buffer
15787                                            .text_for_range(origin.range.clone())
15788                                            .collect::<String>()
15789                                    )
15790                                }),
15791                                HoverLink::InlayHint(_, _) => None,
15792                                HoverLink::Url(_) => None,
15793                                HoverLink::File(_) => None,
15794                            })
15795                            .unwrap_or(tab_kind.to_string());
15796                        let location_tasks = definitions
15797                            .into_iter()
15798                            .map(|definition| match definition {
15799                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15800                                HoverLink::InlayHint(lsp_location, server_id) => editor
15801                                    .compute_target_location(lsp_location, server_id, window, cx),
15802                                HoverLink::Url(_) => Task::ready(Ok(None)),
15803                                HoverLink::File(_) => Task::ready(Ok(None)),
15804                            })
15805                            .collect::<Vec<_>>();
15806                        (title, location_tasks, editor.workspace().clone())
15807                    })
15808                    .context("location tasks preparation")?;
15809
15810                let locations: Vec<Location> = future::join_all(location_tasks)
15811                    .await
15812                    .into_iter()
15813                    .filter_map(|location| location.transpose())
15814                    .collect::<Result<_>>()
15815                    .context("location tasks")?;
15816
15817                if locations.is_empty() {
15818                    return Ok(Navigated::No);
15819                }
15820
15821                let Some(workspace) = workspace else {
15822                    return Ok(Navigated::No);
15823                };
15824
15825                let opened = workspace
15826                    .update_in(cx, |workspace, window, cx| {
15827                        Self::open_locations_in_multibuffer(
15828                            workspace,
15829                            locations,
15830                            title,
15831                            split,
15832                            MultibufferSelectionMode::First,
15833                            window,
15834                            cx,
15835                        )
15836                    })
15837                    .ok();
15838
15839                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15840            })
15841        } else {
15842            Task::ready(Ok(Navigated::No))
15843        }
15844    }
15845
15846    fn compute_target_location(
15847        &self,
15848        lsp_location: lsp::Location,
15849        server_id: LanguageServerId,
15850        window: &mut Window,
15851        cx: &mut Context<Self>,
15852    ) -> Task<anyhow::Result<Option<Location>>> {
15853        let Some(project) = self.project.clone() else {
15854            return Task::ready(Ok(None));
15855        };
15856
15857        cx.spawn_in(window, async move |editor, cx| {
15858            let location_task = editor.update(cx, |_, cx| {
15859                project.update(cx, |project, cx| {
15860                    let language_server_name = project
15861                        .language_server_statuses(cx)
15862                        .find(|(id, _)| server_id == *id)
15863                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15864                    language_server_name.map(|language_server_name| {
15865                        project.open_local_buffer_via_lsp(
15866                            lsp_location.uri.clone(),
15867                            server_id,
15868                            language_server_name,
15869                            cx,
15870                        )
15871                    })
15872                })
15873            })?;
15874            let location = match location_task {
15875                Some(task) => Some({
15876                    let target_buffer_handle = task.await.context("open local buffer")?;
15877                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15878                        let target_start = target_buffer
15879                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15880                        let target_end = target_buffer
15881                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15882                        target_buffer.anchor_after(target_start)
15883                            ..target_buffer.anchor_before(target_end)
15884                    })?;
15885                    Location {
15886                        buffer: target_buffer_handle,
15887                        range,
15888                    }
15889                }),
15890                None => None,
15891            };
15892            Ok(location)
15893        })
15894    }
15895
15896    pub fn find_all_references(
15897        &mut self,
15898        _: &FindAllReferences,
15899        window: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) -> Option<Task<Result<Navigated>>> {
15902        let selection = self.selections.newest::<usize>(cx);
15903        let multi_buffer = self.buffer.read(cx);
15904        let head = selection.head();
15905
15906        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15907        let head_anchor = multi_buffer_snapshot.anchor_at(
15908            head,
15909            if head < selection.tail() {
15910                Bias::Right
15911            } else {
15912                Bias::Left
15913            },
15914        );
15915
15916        match self
15917            .find_all_references_task_sources
15918            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15919        {
15920            Ok(_) => {
15921                log::info!(
15922                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15923                );
15924                return None;
15925            }
15926            Err(i) => {
15927                self.find_all_references_task_sources.insert(i, head_anchor);
15928            }
15929        }
15930
15931        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15932        let workspace = self.workspace()?;
15933        let project = workspace.read(cx).project().clone();
15934        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15935        Some(cx.spawn_in(window, async move |editor, cx| {
15936            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15937                if let Ok(i) = editor
15938                    .find_all_references_task_sources
15939                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15940                {
15941                    editor.find_all_references_task_sources.remove(i);
15942                }
15943            });
15944
15945            let locations = references.await?;
15946            if locations.is_empty() {
15947                return anyhow::Ok(Navigated::No);
15948            }
15949
15950            workspace.update_in(cx, |workspace, window, cx| {
15951                let title = locations
15952                    .first()
15953                    .as_ref()
15954                    .map(|location| {
15955                        let buffer = location.buffer.read(cx);
15956                        format!(
15957                            "References to `{}`",
15958                            buffer
15959                                .text_for_range(location.range.clone())
15960                                .collect::<String>()
15961                        )
15962                    })
15963                    .unwrap();
15964                Self::open_locations_in_multibuffer(
15965                    workspace,
15966                    locations,
15967                    title,
15968                    false,
15969                    MultibufferSelectionMode::First,
15970                    window,
15971                    cx,
15972                );
15973                Navigated::Yes
15974            })
15975        }))
15976    }
15977
15978    /// Opens a multibuffer with the given project locations in it
15979    pub fn open_locations_in_multibuffer(
15980        workspace: &mut Workspace,
15981        mut locations: Vec<Location>,
15982        title: String,
15983        split: bool,
15984        multibuffer_selection_mode: MultibufferSelectionMode,
15985        window: &mut Window,
15986        cx: &mut Context<Workspace>,
15987    ) {
15988        if locations.is_empty() {
15989            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15990            return;
15991        }
15992
15993        // If there are multiple definitions, open them in a multibuffer
15994        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15995        let mut locations = locations.into_iter().peekable();
15996        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15997        let capability = workspace.project().read(cx).capability();
15998
15999        let excerpt_buffer = cx.new(|cx| {
16000            let mut multibuffer = MultiBuffer::new(capability);
16001            while let Some(location) = locations.next() {
16002                let buffer = location.buffer.read(cx);
16003                let mut ranges_for_buffer = Vec::new();
16004                let range = location.range.to_point(buffer);
16005                ranges_for_buffer.push(range.clone());
16006
16007                while let Some(next_location) = locations.peek() {
16008                    if next_location.buffer == location.buffer {
16009                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16010                        locations.next();
16011                    } else {
16012                        break;
16013                    }
16014                }
16015
16016                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16017                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16018                    PathKey::for_buffer(&location.buffer, cx),
16019                    location.buffer.clone(),
16020                    ranges_for_buffer,
16021                    DEFAULT_MULTIBUFFER_CONTEXT,
16022                    cx,
16023                );
16024                ranges.extend(new_ranges)
16025            }
16026
16027            multibuffer.with_title(title)
16028        });
16029
16030        let editor = cx.new(|cx| {
16031            Editor::for_multibuffer(
16032                excerpt_buffer,
16033                Some(workspace.project().clone()),
16034                window,
16035                cx,
16036            )
16037        });
16038        editor.update(cx, |editor, cx| {
16039            match multibuffer_selection_mode {
16040                MultibufferSelectionMode::First => {
16041                    if let Some(first_range) = ranges.first() {
16042                        editor.change_selections(
16043                            SelectionEffects::no_scroll(),
16044                            window,
16045                            cx,
16046                            |selections| {
16047                                selections.clear_disjoint();
16048                                selections
16049                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16050                            },
16051                        );
16052                    }
16053                    editor.highlight_background::<Self>(
16054                        &ranges,
16055                        |theme| theme.colors().editor_highlighted_line_background,
16056                        cx,
16057                    );
16058                }
16059                MultibufferSelectionMode::All => {
16060                    editor.change_selections(
16061                        SelectionEffects::no_scroll(),
16062                        window,
16063                        cx,
16064                        |selections| {
16065                            selections.clear_disjoint();
16066                            selections.select_anchor_ranges(ranges);
16067                        },
16068                    );
16069                }
16070            }
16071            editor.register_buffers_with_language_servers(cx);
16072        });
16073
16074        let item = Box::new(editor);
16075        let item_id = item.item_id();
16076
16077        if split {
16078            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16079        } else {
16080            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16081                let (preview_item_id, preview_item_idx) =
16082                    workspace.active_pane().read_with(cx, |pane, _| {
16083                        (pane.preview_item_id(), pane.preview_item_idx())
16084                    });
16085
16086                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16087
16088                if let Some(preview_item_id) = preview_item_id {
16089                    workspace.active_pane().update(cx, |pane, cx| {
16090                        pane.remove_item(preview_item_id, false, false, window, cx);
16091                    });
16092                }
16093            } else {
16094                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16095            }
16096        }
16097        workspace.active_pane().update(cx, |pane, cx| {
16098            pane.set_preview_item_id(Some(item_id), cx);
16099        });
16100    }
16101
16102    pub fn rename(
16103        &mut self,
16104        _: &Rename,
16105        window: &mut Window,
16106        cx: &mut Context<Self>,
16107    ) -> Option<Task<Result<()>>> {
16108        use language::ToOffset as _;
16109
16110        let provider = self.semantics_provider.clone()?;
16111        let selection = self.selections.newest_anchor().clone();
16112        let (cursor_buffer, cursor_buffer_position) = self
16113            .buffer
16114            .read(cx)
16115            .text_anchor_for_position(selection.head(), cx)?;
16116        let (tail_buffer, cursor_buffer_position_end) = self
16117            .buffer
16118            .read(cx)
16119            .text_anchor_for_position(selection.tail(), cx)?;
16120        if tail_buffer != cursor_buffer {
16121            return None;
16122        }
16123
16124        let snapshot = cursor_buffer.read(cx).snapshot();
16125        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16126        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16127        let prepare_rename = provider
16128            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16129            .unwrap_or_else(|| Task::ready(Ok(None)));
16130        drop(snapshot);
16131
16132        Some(cx.spawn_in(window, async move |this, cx| {
16133            let rename_range = if let Some(range) = prepare_rename.await? {
16134                Some(range)
16135            } else {
16136                this.update(cx, |this, cx| {
16137                    let buffer = this.buffer.read(cx).snapshot(cx);
16138                    let mut buffer_highlights = this
16139                        .document_highlights_for_position(selection.head(), &buffer)
16140                        .filter(|highlight| {
16141                            highlight.start.excerpt_id == selection.head().excerpt_id
16142                                && highlight.end.excerpt_id == selection.head().excerpt_id
16143                        });
16144                    buffer_highlights
16145                        .next()
16146                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16147                })?
16148            };
16149            if let Some(rename_range) = rename_range {
16150                this.update_in(cx, |this, window, cx| {
16151                    let snapshot = cursor_buffer.read(cx).snapshot();
16152                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16153                    let cursor_offset_in_rename_range =
16154                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16155                    let cursor_offset_in_rename_range_end =
16156                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16157
16158                    this.take_rename(false, window, cx);
16159                    let buffer = this.buffer.read(cx).read(cx);
16160                    let cursor_offset = selection.head().to_offset(&buffer);
16161                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16162                    let rename_end = rename_start + rename_buffer_range.len();
16163                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16164                    let mut old_highlight_id = None;
16165                    let old_name: Arc<str> = buffer
16166                        .chunks(rename_start..rename_end, true)
16167                        .map(|chunk| {
16168                            if old_highlight_id.is_none() {
16169                                old_highlight_id = chunk.syntax_highlight_id;
16170                            }
16171                            chunk.text
16172                        })
16173                        .collect::<String>()
16174                        .into();
16175
16176                    drop(buffer);
16177
16178                    // Position the selection in the rename editor so that it matches the current selection.
16179                    this.show_local_selections = false;
16180                    let rename_editor = cx.new(|cx| {
16181                        let mut editor = Editor::single_line(window, cx);
16182                        editor.buffer.update(cx, |buffer, cx| {
16183                            buffer.edit([(0..0, old_name.clone())], None, cx)
16184                        });
16185                        let rename_selection_range = match cursor_offset_in_rename_range
16186                            .cmp(&cursor_offset_in_rename_range_end)
16187                        {
16188                            Ordering::Equal => {
16189                                editor.select_all(&SelectAll, window, cx);
16190                                return editor;
16191                            }
16192                            Ordering::Less => {
16193                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16194                            }
16195                            Ordering::Greater => {
16196                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16197                            }
16198                        };
16199                        if rename_selection_range.end > old_name.len() {
16200                            editor.select_all(&SelectAll, window, cx);
16201                        } else {
16202                            editor.change_selections(Default::default(), window, cx, |s| {
16203                                s.select_ranges([rename_selection_range]);
16204                            });
16205                        }
16206                        editor
16207                    });
16208                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16209                        if e == &EditorEvent::Focused {
16210                            cx.emit(EditorEvent::FocusedIn)
16211                        }
16212                    })
16213                    .detach();
16214
16215                    let write_highlights =
16216                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16217                    let read_highlights =
16218                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16219                    let ranges = write_highlights
16220                        .iter()
16221                        .flat_map(|(_, ranges)| ranges.iter())
16222                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16223                        .cloned()
16224                        .collect();
16225
16226                    this.highlight_text::<Rename>(
16227                        ranges,
16228                        HighlightStyle {
16229                            fade_out: Some(0.6),
16230                            ..Default::default()
16231                        },
16232                        cx,
16233                    );
16234                    let rename_focus_handle = rename_editor.focus_handle(cx);
16235                    window.focus(&rename_focus_handle);
16236                    let block_id = this.insert_blocks(
16237                        [BlockProperties {
16238                            style: BlockStyle::Flex,
16239                            placement: BlockPlacement::Below(range.start),
16240                            height: Some(1),
16241                            render: Arc::new({
16242                                let rename_editor = rename_editor.clone();
16243                                move |cx: &mut BlockContext| {
16244                                    let mut text_style = cx.editor_style.text.clone();
16245                                    if let Some(highlight_style) = old_highlight_id
16246                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16247                                    {
16248                                        text_style = text_style.highlight(highlight_style);
16249                                    }
16250                                    div()
16251                                        .block_mouse_except_scroll()
16252                                        .pl(cx.anchor_x)
16253                                        .child(EditorElement::new(
16254                                            &rename_editor,
16255                                            EditorStyle {
16256                                                background: cx.theme().system().transparent,
16257                                                local_player: cx.editor_style.local_player,
16258                                                text: text_style,
16259                                                scrollbar_width: cx.editor_style.scrollbar_width,
16260                                                syntax: cx.editor_style.syntax.clone(),
16261                                                status: cx.editor_style.status.clone(),
16262                                                inlay_hints_style: HighlightStyle {
16263                                                    font_weight: Some(FontWeight::BOLD),
16264                                                    ..make_inlay_hints_style(cx.app)
16265                                                },
16266                                                inline_completion_styles: make_suggestion_styles(
16267                                                    cx.app,
16268                                                ),
16269                                                ..EditorStyle::default()
16270                                            },
16271                                        ))
16272                                        .into_any_element()
16273                                }
16274                            }),
16275                            priority: 0,
16276                        }],
16277                        Some(Autoscroll::fit()),
16278                        cx,
16279                    )[0];
16280                    this.pending_rename = Some(RenameState {
16281                        range,
16282                        old_name,
16283                        editor: rename_editor,
16284                        block_id,
16285                    });
16286                })?;
16287            }
16288
16289            Ok(())
16290        }))
16291    }
16292
16293    pub fn confirm_rename(
16294        &mut self,
16295        _: &ConfirmRename,
16296        window: &mut Window,
16297        cx: &mut Context<Self>,
16298    ) -> Option<Task<Result<()>>> {
16299        let rename = self.take_rename(false, window, cx)?;
16300        let workspace = self.workspace()?.downgrade();
16301        let (buffer, start) = self
16302            .buffer
16303            .read(cx)
16304            .text_anchor_for_position(rename.range.start, cx)?;
16305        let (end_buffer, _) = self
16306            .buffer
16307            .read(cx)
16308            .text_anchor_for_position(rename.range.end, cx)?;
16309        if buffer != end_buffer {
16310            return None;
16311        }
16312
16313        let old_name = rename.old_name;
16314        let new_name = rename.editor.read(cx).text(cx);
16315
16316        let rename = self.semantics_provider.as_ref()?.perform_rename(
16317            &buffer,
16318            start,
16319            new_name.clone(),
16320            cx,
16321        )?;
16322
16323        Some(cx.spawn_in(window, async move |editor, cx| {
16324            let project_transaction = rename.await?;
16325            Self::open_project_transaction(
16326                &editor,
16327                workspace,
16328                project_transaction,
16329                format!("Rename: {}{}", old_name, new_name),
16330                cx,
16331            )
16332            .await?;
16333
16334            editor.update(cx, |editor, cx| {
16335                editor.refresh_document_highlights(cx);
16336            })?;
16337            Ok(())
16338        }))
16339    }
16340
16341    fn take_rename(
16342        &mut self,
16343        moving_cursor: bool,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) -> Option<RenameState> {
16347        let rename = self.pending_rename.take()?;
16348        if rename.editor.focus_handle(cx).is_focused(window) {
16349            window.focus(&self.focus_handle);
16350        }
16351
16352        self.remove_blocks(
16353            [rename.block_id].into_iter().collect(),
16354            Some(Autoscroll::fit()),
16355            cx,
16356        );
16357        self.clear_highlights::<Rename>(cx);
16358        self.show_local_selections = true;
16359
16360        if moving_cursor {
16361            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16362                editor.selections.newest::<usize>(cx).head()
16363            });
16364
16365            // Update the selection to match the position of the selection inside
16366            // the rename editor.
16367            let snapshot = self.buffer.read(cx).read(cx);
16368            let rename_range = rename.range.to_offset(&snapshot);
16369            let cursor_in_editor = snapshot
16370                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16371                .min(rename_range.end);
16372            drop(snapshot);
16373
16374            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16375                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16376            });
16377        } else {
16378            self.refresh_document_highlights(cx);
16379        }
16380
16381        Some(rename)
16382    }
16383
16384    pub fn pending_rename(&self) -> Option<&RenameState> {
16385        self.pending_rename.as_ref()
16386    }
16387
16388    fn format(
16389        &mut self,
16390        _: &Format,
16391        window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) -> Option<Task<Result<()>>> {
16394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16395
16396        let project = match &self.project {
16397            Some(project) => project.clone(),
16398            None => return None,
16399        };
16400
16401        Some(self.perform_format(
16402            project,
16403            FormatTrigger::Manual,
16404            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16405            window,
16406            cx,
16407        ))
16408    }
16409
16410    fn format_selections(
16411        &mut self,
16412        _: &FormatSelections,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Option<Task<Result<()>>> {
16416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16417
16418        let project = match &self.project {
16419            Some(project) => project.clone(),
16420            None => return None,
16421        };
16422
16423        let ranges = self
16424            .selections
16425            .all_adjusted(cx)
16426            .into_iter()
16427            .map(|selection| selection.range())
16428            .collect_vec();
16429
16430        Some(self.perform_format(
16431            project,
16432            FormatTrigger::Manual,
16433            FormatTarget::Ranges(ranges),
16434            window,
16435            cx,
16436        ))
16437    }
16438
16439    fn perform_format(
16440        &mut self,
16441        project: Entity<Project>,
16442        trigger: FormatTrigger,
16443        target: FormatTarget,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) -> Task<Result<()>> {
16447        let buffer = self.buffer.clone();
16448        let (buffers, target) = match target {
16449            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16450            FormatTarget::Ranges(selection_ranges) => {
16451                let multi_buffer = buffer.read(cx);
16452                let snapshot = multi_buffer.read(cx);
16453                let mut buffers = HashSet::default();
16454                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16455                    BTreeMap::new();
16456                for selection_range in selection_ranges {
16457                    for (buffer, buffer_range, _) in
16458                        snapshot.range_to_buffer_ranges(selection_range)
16459                    {
16460                        let buffer_id = buffer.remote_id();
16461                        let start = buffer.anchor_before(buffer_range.start);
16462                        let end = buffer.anchor_after(buffer_range.end);
16463                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16464                        buffer_id_to_ranges
16465                            .entry(buffer_id)
16466                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16467                            .or_insert_with(|| vec![start..end]);
16468                    }
16469                }
16470                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16471            }
16472        };
16473
16474        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16475        let selections_prev = transaction_id_prev
16476            .and_then(|transaction_id_prev| {
16477                // default to selections as they were after the last edit, if we have them,
16478                // instead of how they are now.
16479                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16480                // will take you back to where you made the last edit, instead of staying where you scrolled
16481                self.selection_history
16482                    .transaction(transaction_id_prev)
16483                    .map(|t| t.0.clone())
16484            })
16485            .unwrap_or_else(|| {
16486                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16487                self.selections.disjoint_anchors()
16488            });
16489
16490        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16491        let format = project.update(cx, |project, cx| {
16492            project.format(buffers, target, true, trigger, cx)
16493        });
16494
16495        cx.spawn_in(window, async move |editor, cx| {
16496            let transaction = futures::select_biased! {
16497                transaction = format.log_err().fuse() => transaction,
16498                () = timeout => {
16499                    log::warn!("timed out waiting for formatting");
16500                    None
16501                }
16502            };
16503
16504            buffer
16505                .update(cx, |buffer, cx| {
16506                    if let Some(transaction) = transaction {
16507                        if !buffer.is_singleton() {
16508                            buffer.push_transaction(&transaction.0, cx);
16509                        }
16510                    }
16511                    cx.notify();
16512                })
16513                .ok();
16514
16515            if let Some(transaction_id_now) =
16516                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16517            {
16518                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16519                if has_new_transaction {
16520                    _ = editor.update(cx, |editor, _| {
16521                        editor
16522                            .selection_history
16523                            .insert_transaction(transaction_id_now, selections_prev);
16524                    });
16525                }
16526            }
16527
16528            Ok(())
16529        })
16530    }
16531
16532    fn organize_imports(
16533        &mut self,
16534        _: &OrganizeImports,
16535        window: &mut Window,
16536        cx: &mut Context<Self>,
16537    ) -> Option<Task<Result<()>>> {
16538        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16539        let project = match &self.project {
16540            Some(project) => project.clone(),
16541            None => return None,
16542        };
16543        Some(self.perform_code_action_kind(
16544            project,
16545            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16546            window,
16547            cx,
16548        ))
16549    }
16550
16551    fn perform_code_action_kind(
16552        &mut self,
16553        project: Entity<Project>,
16554        kind: CodeActionKind,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) -> Task<Result<()>> {
16558        let buffer = self.buffer.clone();
16559        let buffers = buffer.read(cx).all_buffers();
16560        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16561        let apply_action = project.update(cx, |project, cx| {
16562            project.apply_code_action_kind(buffers, kind, true, cx)
16563        });
16564        cx.spawn_in(window, async move |_, cx| {
16565            let transaction = futures::select_biased! {
16566                () = timeout => {
16567                    log::warn!("timed out waiting for executing code action");
16568                    None
16569                }
16570                transaction = apply_action.log_err().fuse() => transaction,
16571            };
16572            buffer
16573                .update(cx, |buffer, cx| {
16574                    // check if we need this
16575                    if let Some(transaction) = transaction {
16576                        if !buffer.is_singleton() {
16577                            buffer.push_transaction(&transaction.0, cx);
16578                        }
16579                    }
16580                    cx.notify();
16581                })
16582                .ok();
16583            Ok(())
16584        })
16585    }
16586
16587    pub fn restart_language_server(
16588        &mut self,
16589        _: &RestartLanguageServer,
16590        _: &mut Window,
16591        cx: &mut Context<Self>,
16592    ) {
16593        if let Some(project) = self.project.clone() {
16594            self.buffer.update(cx, |multi_buffer, cx| {
16595                project.update(cx, |project, cx| {
16596                    project.restart_language_servers_for_buffers(
16597                        multi_buffer.all_buffers().into_iter().collect(),
16598                        HashSet::default(),
16599                        cx,
16600                    );
16601                });
16602            })
16603        }
16604    }
16605
16606    pub fn stop_language_server(
16607        &mut self,
16608        _: &StopLanguageServer,
16609        _: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) {
16612        if let Some(project) = self.project.clone() {
16613            self.buffer.update(cx, |multi_buffer, cx| {
16614                project.update(cx, |project, cx| {
16615                    project.stop_language_servers_for_buffers(
16616                        multi_buffer.all_buffers().into_iter().collect(),
16617                        HashSet::default(),
16618                        cx,
16619                    );
16620                    cx.emit(project::Event::RefreshInlayHints);
16621                });
16622            });
16623        }
16624    }
16625
16626    fn cancel_language_server_work(
16627        workspace: &mut Workspace,
16628        _: &actions::CancelLanguageServerWork,
16629        _: &mut Window,
16630        cx: &mut Context<Workspace>,
16631    ) {
16632        let project = workspace.project();
16633        let buffers = workspace
16634            .active_item(cx)
16635            .and_then(|item| item.act_as::<Editor>(cx))
16636            .map_or(HashSet::default(), |editor| {
16637                editor.read(cx).buffer.read(cx).all_buffers()
16638            });
16639        project.update(cx, |project, cx| {
16640            project.cancel_language_server_work_for_buffers(buffers, cx);
16641        });
16642    }
16643
16644    fn show_character_palette(
16645        &mut self,
16646        _: &ShowCharacterPalette,
16647        window: &mut Window,
16648        _: &mut Context<Self>,
16649    ) {
16650        window.show_character_palette();
16651    }
16652
16653    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16654        if !self.diagnostics_enabled() {
16655            return;
16656        }
16657
16658        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16659            let buffer = self.buffer.read(cx).snapshot(cx);
16660            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16661            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16662            let is_valid = buffer
16663                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16664                .any(|entry| {
16665                    entry.diagnostic.is_primary
16666                        && !entry.range.is_empty()
16667                        && entry.range.start == primary_range_start
16668                        && entry.diagnostic.message == active_diagnostics.active_message
16669                });
16670
16671            if !is_valid {
16672                self.dismiss_diagnostics(cx);
16673            }
16674        }
16675    }
16676
16677    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16678        match &self.active_diagnostics {
16679            ActiveDiagnostic::Group(group) => Some(group),
16680            _ => None,
16681        }
16682    }
16683
16684    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16685        if !self.diagnostics_enabled() {
16686            return;
16687        }
16688        self.dismiss_diagnostics(cx);
16689        self.active_diagnostics = ActiveDiagnostic::All;
16690    }
16691
16692    fn activate_diagnostics(
16693        &mut self,
16694        buffer_id: BufferId,
16695        diagnostic: DiagnosticEntry<usize>,
16696        window: &mut Window,
16697        cx: &mut Context<Self>,
16698    ) {
16699        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16700            return;
16701        }
16702        self.dismiss_diagnostics(cx);
16703        let snapshot = self.snapshot(window, cx);
16704        let buffer = self.buffer.read(cx).snapshot(cx);
16705        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16706            return;
16707        };
16708
16709        let diagnostic_group = buffer
16710            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16711            .collect::<Vec<_>>();
16712
16713        let blocks =
16714            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16715
16716        let blocks = self.display_map.update(cx, |display_map, cx| {
16717            display_map.insert_blocks(blocks, cx).into_iter().collect()
16718        });
16719        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16720            active_range: buffer.anchor_before(diagnostic.range.start)
16721                ..buffer.anchor_after(diagnostic.range.end),
16722            active_message: diagnostic.diagnostic.message.clone(),
16723            group_id: diagnostic.diagnostic.group_id,
16724            blocks,
16725        });
16726        cx.notify();
16727    }
16728
16729    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16730        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16731            return;
16732        };
16733
16734        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16735        if let ActiveDiagnostic::Group(group) = prev {
16736            self.display_map.update(cx, |display_map, cx| {
16737                display_map.remove_blocks(group.blocks, cx);
16738            });
16739            cx.notify();
16740        }
16741    }
16742
16743    /// Disable inline diagnostics rendering for this editor.
16744    pub fn disable_inline_diagnostics(&mut self) {
16745        self.inline_diagnostics_enabled = false;
16746        self.inline_diagnostics_update = Task::ready(());
16747        self.inline_diagnostics.clear();
16748    }
16749
16750    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16751        self.diagnostics_enabled = false;
16752        self.dismiss_diagnostics(cx);
16753        self.inline_diagnostics_update = Task::ready(());
16754        self.inline_diagnostics.clear();
16755    }
16756
16757    pub fn diagnostics_enabled(&self) -> bool {
16758        self.diagnostics_enabled && self.mode.is_full()
16759    }
16760
16761    pub fn inline_diagnostics_enabled(&self) -> bool {
16762        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16763    }
16764
16765    pub fn show_inline_diagnostics(&self) -> bool {
16766        self.show_inline_diagnostics
16767    }
16768
16769    pub fn toggle_inline_diagnostics(
16770        &mut self,
16771        _: &ToggleInlineDiagnostics,
16772        window: &mut Window,
16773        cx: &mut Context<Editor>,
16774    ) {
16775        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16776        self.refresh_inline_diagnostics(false, window, cx);
16777    }
16778
16779    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16780        self.diagnostics_max_severity = severity;
16781        self.display_map.update(cx, |display_map, _| {
16782            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16783        });
16784    }
16785
16786    pub fn toggle_diagnostics(
16787        &mut self,
16788        _: &ToggleDiagnostics,
16789        window: &mut Window,
16790        cx: &mut Context<Editor>,
16791    ) {
16792        if !self.diagnostics_enabled() {
16793            return;
16794        }
16795
16796        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16797            EditorSettings::get_global(cx)
16798                .diagnostics_max_severity
16799                .filter(|severity| severity != &DiagnosticSeverity::Off)
16800                .unwrap_or(DiagnosticSeverity::Hint)
16801        } else {
16802            DiagnosticSeverity::Off
16803        };
16804        self.set_max_diagnostics_severity(new_severity, cx);
16805        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16806            self.active_diagnostics = ActiveDiagnostic::None;
16807            self.inline_diagnostics_update = Task::ready(());
16808            self.inline_diagnostics.clear();
16809        } else {
16810            self.refresh_inline_diagnostics(false, window, cx);
16811        }
16812
16813        cx.notify();
16814    }
16815
16816    pub fn toggle_minimap(
16817        &mut self,
16818        _: &ToggleMinimap,
16819        window: &mut Window,
16820        cx: &mut Context<Editor>,
16821    ) {
16822        if self.supports_minimap(cx) {
16823            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16824        }
16825    }
16826
16827    fn refresh_inline_diagnostics(
16828        &mut self,
16829        debounce: bool,
16830        window: &mut Window,
16831        cx: &mut Context<Self>,
16832    ) {
16833        let max_severity = ProjectSettings::get_global(cx)
16834            .diagnostics
16835            .inline
16836            .max_severity
16837            .unwrap_or(self.diagnostics_max_severity);
16838
16839        if !self.inline_diagnostics_enabled()
16840            || !self.show_inline_diagnostics
16841            || max_severity == DiagnosticSeverity::Off
16842        {
16843            self.inline_diagnostics_update = Task::ready(());
16844            self.inline_diagnostics.clear();
16845            return;
16846        }
16847
16848        let debounce_ms = ProjectSettings::get_global(cx)
16849            .diagnostics
16850            .inline
16851            .update_debounce_ms;
16852        let debounce = if debounce && debounce_ms > 0 {
16853            Some(Duration::from_millis(debounce_ms))
16854        } else {
16855            None
16856        };
16857        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16858            if let Some(debounce) = debounce {
16859                cx.background_executor().timer(debounce).await;
16860            }
16861            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16862                editor
16863                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16864                    .ok()
16865            }) else {
16866                return;
16867            };
16868
16869            let new_inline_diagnostics = cx
16870                .background_spawn(async move {
16871                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16872                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16873                        let message = diagnostic_entry
16874                            .diagnostic
16875                            .message
16876                            .split_once('\n')
16877                            .map(|(line, _)| line)
16878                            .map(SharedString::new)
16879                            .unwrap_or_else(|| {
16880                                SharedString::from(diagnostic_entry.diagnostic.message)
16881                            });
16882                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16883                        let (Ok(i) | Err(i)) = inline_diagnostics
16884                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16885                        inline_diagnostics.insert(
16886                            i,
16887                            (
16888                                start_anchor,
16889                                InlineDiagnostic {
16890                                    message,
16891                                    group_id: diagnostic_entry.diagnostic.group_id,
16892                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16893                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16894                                    severity: diagnostic_entry.diagnostic.severity,
16895                                },
16896                            ),
16897                        );
16898                    }
16899                    inline_diagnostics
16900                })
16901                .await;
16902
16903            editor
16904                .update(cx, |editor, cx| {
16905                    editor.inline_diagnostics = new_inline_diagnostics;
16906                    cx.notify();
16907                })
16908                .ok();
16909        });
16910    }
16911
16912    fn pull_diagnostics(
16913        &mut self,
16914        buffer_id: Option<BufferId>,
16915        window: &Window,
16916        cx: &mut Context<Self>,
16917    ) -> Option<()> {
16918        if !self.mode().is_full() {
16919            return None;
16920        }
16921        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16922            .diagnostics
16923            .lsp_pull_diagnostics;
16924        if !pull_diagnostics_settings.enabled {
16925            return None;
16926        }
16927        let project = self.project.as_ref()?.downgrade();
16928        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16929        let mut buffers = self.buffer.read(cx).all_buffers();
16930        if let Some(buffer_id) = buffer_id {
16931            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16932        }
16933
16934        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16935            cx.background_executor().timer(debounce).await;
16936
16937            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16938                buffers
16939                    .into_iter()
16940                    .filter_map(|buffer| {
16941                        project
16942                            .update(cx, |project, cx| {
16943                                project.lsp_store().update(cx, |lsp_store, cx| {
16944                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16945                                })
16946                            })
16947                            .ok()
16948                    })
16949                    .collect::<FuturesUnordered<_>>()
16950            }) else {
16951                return;
16952            };
16953
16954            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16955                match pull_task {
16956                    Ok(()) => {
16957                        if editor
16958                            .update_in(cx, |editor, window, cx| {
16959                                editor.update_diagnostics_state(window, cx);
16960                            })
16961                            .is_err()
16962                        {
16963                            return;
16964                        }
16965                    }
16966                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16967                }
16968            }
16969        });
16970
16971        Some(())
16972    }
16973
16974    pub fn set_selections_from_remote(
16975        &mut self,
16976        selections: Vec<Selection<Anchor>>,
16977        pending_selection: Option<Selection<Anchor>>,
16978        window: &mut Window,
16979        cx: &mut Context<Self>,
16980    ) {
16981        let old_cursor_position = self.selections.newest_anchor().head();
16982        self.selections.change_with(cx, |s| {
16983            s.select_anchors(selections);
16984            if let Some(pending_selection) = pending_selection {
16985                s.set_pending(pending_selection, SelectMode::Character);
16986            } else {
16987                s.clear_pending();
16988            }
16989        });
16990        self.selections_did_change(
16991            false,
16992            &old_cursor_position,
16993            SelectionEffects::default(),
16994            window,
16995            cx,
16996        );
16997    }
16998
16999    pub fn transact(
17000        &mut self,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17004    ) -> Option<TransactionId> {
17005        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17006            this.start_transaction_at(Instant::now(), window, cx);
17007            update(this, window, cx);
17008            this.end_transaction_at(Instant::now(), cx)
17009        })
17010    }
17011
17012    pub fn start_transaction_at(
17013        &mut self,
17014        now: Instant,
17015        window: &mut Window,
17016        cx: &mut Context<Self>,
17017    ) -> Option<TransactionId> {
17018        self.end_selection(window, cx);
17019        if let Some(tx_id) = self
17020            .buffer
17021            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17022        {
17023            self.selection_history
17024                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17025            cx.emit(EditorEvent::TransactionBegun {
17026                transaction_id: tx_id,
17027            });
17028            Some(tx_id)
17029        } else {
17030            None
17031        }
17032    }
17033
17034    pub fn end_transaction_at(
17035        &mut self,
17036        now: Instant,
17037        cx: &mut Context<Self>,
17038    ) -> Option<TransactionId> {
17039        if let Some(transaction_id) = self
17040            .buffer
17041            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17042        {
17043            if let Some((_, end_selections)) =
17044                self.selection_history.transaction_mut(transaction_id)
17045            {
17046                *end_selections = Some(self.selections.disjoint_anchors());
17047            } else {
17048                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17049            }
17050
17051            cx.emit(EditorEvent::Edited { transaction_id });
17052            Some(transaction_id)
17053        } else {
17054            None
17055        }
17056    }
17057
17058    pub fn modify_transaction_selection_history(
17059        &mut self,
17060        transaction_id: TransactionId,
17061        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17062    ) -> bool {
17063        self.selection_history
17064            .transaction_mut(transaction_id)
17065            .map(modify)
17066            .is_some()
17067    }
17068
17069    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17070        if self.selection_mark_mode {
17071            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17072                s.move_with(|_, sel| {
17073                    sel.collapse_to(sel.head(), SelectionGoal::None);
17074                });
17075            })
17076        }
17077        self.selection_mark_mode = true;
17078        cx.notify();
17079    }
17080
17081    pub fn swap_selection_ends(
17082        &mut self,
17083        _: &actions::SwapSelectionEnds,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17088            s.move_with(|_, sel| {
17089                if sel.start != sel.end {
17090                    sel.reversed = !sel.reversed
17091                }
17092            });
17093        });
17094        self.request_autoscroll(Autoscroll::newest(), cx);
17095        cx.notify();
17096    }
17097
17098    pub fn toggle_focus(
17099        workspace: &mut Workspace,
17100        _: &actions::ToggleFocus,
17101        window: &mut Window,
17102        cx: &mut Context<Workspace>,
17103    ) {
17104        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17105            return;
17106        };
17107        workspace.activate_item(&item, true, true, window, cx);
17108    }
17109
17110    pub fn toggle_fold(
17111        &mut self,
17112        _: &actions::ToggleFold,
17113        window: &mut Window,
17114        cx: &mut Context<Self>,
17115    ) {
17116        if self.is_singleton(cx) {
17117            let selection = self.selections.newest::<Point>(cx);
17118
17119            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17120            let range = if selection.is_empty() {
17121                let point = selection.head().to_display_point(&display_map);
17122                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17123                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17124                    .to_point(&display_map);
17125                start..end
17126            } else {
17127                selection.range()
17128            };
17129            if display_map.folds_in_range(range).next().is_some() {
17130                self.unfold_lines(&Default::default(), window, cx)
17131            } else {
17132                self.fold(&Default::default(), window, cx)
17133            }
17134        } else {
17135            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17136            let buffer_ids: HashSet<_> = self
17137                .selections
17138                .disjoint_anchor_ranges()
17139                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17140                .collect();
17141
17142            let should_unfold = buffer_ids
17143                .iter()
17144                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17145
17146            for buffer_id in buffer_ids {
17147                if should_unfold {
17148                    self.unfold_buffer(buffer_id, cx);
17149                } else {
17150                    self.fold_buffer(buffer_id, cx);
17151                }
17152            }
17153        }
17154    }
17155
17156    pub fn toggle_fold_recursive(
17157        &mut self,
17158        _: &actions::ToggleFoldRecursive,
17159        window: &mut Window,
17160        cx: &mut Context<Self>,
17161    ) {
17162        let selection = self.selections.newest::<Point>(cx);
17163
17164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17165        let range = if selection.is_empty() {
17166            let point = selection.head().to_display_point(&display_map);
17167            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17168            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17169                .to_point(&display_map);
17170            start..end
17171        } else {
17172            selection.range()
17173        };
17174        if display_map.folds_in_range(range).next().is_some() {
17175            self.unfold_recursive(&Default::default(), window, cx)
17176        } else {
17177            self.fold_recursive(&Default::default(), window, cx)
17178        }
17179    }
17180
17181    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17182        if self.is_singleton(cx) {
17183            let mut to_fold = Vec::new();
17184            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17185            let selections = self.selections.all_adjusted(cx);
17186
17187            for selection in selections {
17188                let range = selection.range().sorted();
17189                let buffer_start_row = range.start.row;
17190
17191                if range.start.row != range.end.row {
17192                    let mut found = false;
17193                    let mut row = range.start.row;
17194                    while row <= range.end.row {
17195                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17196                        {
17197                            found = true;
17198                            row = crease.range().end.row + 1;
17199                            to_fold.push(crease);
17200                        } else {
17201                            row += 1
17202                        }
17203                    }
17204                    if found {
17205                        continue;
17206                    }
17207                }
17208
17209                for row in (0..=range.start.row).rev() {
17210                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17211                        if crease.range().end.row >= buffer_start_row {
17212                            to_fold.push(crease);
17213                            if row <= range.start.row {
17214                                break;
17215                            }
17216                        }
17217                    }
17218                }
17219            }
17220
17221            self.fold_creases(to_fold, true, window, cx);
17222        } else {
17223            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17224            let buffer_ids = self
17225                .selections
17226                .disjoint_anchor_ranges()
17227                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17228                .collect::<HashSet<_>>();
17229            for buffer_id in buffer_ids {
17230                self.fold_buffer(buffer_id, cx);
17231            }
17232        }
17233    }
17234
17235    pub fn toggle_fold_all(
17236        &mut self,
17237        _: &actions::ToggleFoldAll,
17238        window: &mut Window,
17239        cx: &mut Context<Self>,
17240    ) {
17241        if self.buffer.read(cx).is_singleton() {
17242            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17243            let has_folds = display_map
17244                .folds_in_range(0..display_map.buffer_snapshot.len())
17245                .next()
17246                .is_some();
17247
17248            if has_folds {
17249                self.unfold_all(&actions::UnfoldAll, window, cx);
17250            } else {
17251                self.fold_all(&actions::FoldAll, window, cx);
17252            }
17253        } else {
17254            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17255            let should_unfold = buffer_ids
17256                .iter()
17257                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17258
17259            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17260                editor
17261                    .update_in(cx, |editor, _, cx| {
17262                        for buffer_id in buffer_ids {
17263                            if should_unfold {
17264                                editor.unfold_buffer(buffer_id, cx);
17265                            } else {
17266                                editor.fold_buffer(buffer_id, cx);
17267                            }
17268                        }
17269                    })
17270                    .ok();
17271            });
17272        }
17273    }
17274
17275    fn fold_at_level(
17276        &mut self,
17277        fold_at: &FoldAtLevel,
17278        window: &mut Window,
17279        cx: &mut Context<Self>,
17280    ) {
17281        if !self.buffer.read(cx).is_singleton() {
17282            return;
17283        }
17284
17285        let fold_at_level = fold_at.0;
17286        let snapshot = self.buffer.read(cx).snapshot(cx);
17287        let mut to_fold = Vec::new();
17288        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17289
17290        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17291            while start_row < end_row {
17292                match self
17293                    .snapshot(window, cx)
17294                    .crease_for_buffer_row(MultiBufferRow(start_row))
17295                {
17296                    Some(crease) => {
17297                        let nested_start_row = crease.range().start.row + 1;
17298                        let nested_end_row = crease.range().end.row;
17299
17300                        if current_level < fold_at_level {
17301                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17302                        } else if current_level == fold_at_level {
17303                            to_fold.push(crease);
17304                        }
17305
17306                        start_row = nested_end_row + 1;
17307                    }
17308                    None => start_row += 1,
17309                }
17310            }
17311        }
17312
17313        self.fold_creases(to_fold, true, window, cx);
17314    }
17315
17316    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17317        if self.buffer.read(cx).is_singleton() {
17318            let mut fold_ranges = Vec::new();
17319            let snapshot = self.buffer.read(cx).snapshot(cx);
17320
17321            for row in 0..snapshot.max_row().0 {
17322                if let Some(foldable_range) = self
17323                    .snapshot(window, cx)
17324                    .crease_for_buffer_row(MultiBufferRow(row))
17325                {
17326                    fold_ranges.push(foldable_range);
17327                }
17328            }
17329
17330            self.fold_creases(fold_ranges, true, window, cx);
17331        } else {
17332            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17333                editor
17334                    .update_in(cx, |editor, _, cx| {
17335                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17336                            editor.fold_buffer(buffer_id, cx);
17337                        }
17338                    })
17339                    .ok();
17340            });
17341        }
17342    }
17343
17344    pub fn fold_function_bodies(
17345        &mut self,
17346        _: &actions::FoldFunctionBodies,
17347        window: &mut Window,
17348        cx: &mut Context<Self>,
17349    ) {
17350        let snapshot = self.buffer.read(cx).snapshot(cx);
17351
17352        let ranges = snapshot
17353            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17354            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17355            .collect::<Vec<_>>();
17356
17357        let creases = ranges
17358            .into_iter()
17359            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17360            .collect();
17361
17362        self.fold_creases(creases, true, window, cx);
17363    }
17364
17365    pub fn fold_recursive(
17366        &mut self,
17367        _: &actions::FoldRecursive,
17368        window: &mut Window,
17369        cx: &mut Context<Self>,
17370    ) {
17371        let mut to_fold = Vec::new();
17372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17373        let selections = self.selections.all_adjusted(cx);
17374
17375        for selection in selections {
17376            let range = selection.range().sorted();
17377            let buffer_start_row = range.start.row;
17378
17379            if range.start.row != range.end.row {
17380                let mut found = false;
17381                for row in range.start.row..=range.end.row {
17382                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17383                        found = true;
17384                        to_fold.push(crease);
17385                    }
17386                }
17387                if found {
17388                    continue;
17389                }
17390            }
17391
17392            for row in (0..=range.start.row).rev() {
17393                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17394                    if crease.range().end.row >= buffer_start_row {
17395                        to_fold.push(crease);
17396                    } else {
17397                        break;
17398                    }
17399                }
17400            }
17401        }
17402
17403        self.fold_creases(to_fold, true, window, cx);
17404    }
17405
17406    pub fn fold_at(
17407        &mut self,
17408        buffer_row: MultiBufferRow,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17413
17414        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17415            let autoscroll = self
17416                .selections
17417                .all::<Point>(cx)
17418                .iter()
17419                .any(|selection| crease.range().overlaps(&selection.range()));
17420
17421            self.fold_creases(vec![crease], autoscroll, window, cx);
17422        }
17423    }
17424
17425    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17426        if self.is_singleton(cx) {
17427            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17428            let buffer = &display_map.buffer_snapshot;
17429            let selections = self.selections.all::<Point>(cx);
17430            let ranges = selections
17431                .iter()
17432                .map(|s| {
17433                    let range = s.display_range(&display_map).sorted();
17434                    let mut start = range.start.to_point(&display_map);
17435                    let mut end = range.end.to_point(&display_map);
17436                    start.column = 0;
17437                    end.column = buffer.line_len(MultiBufferRow(end.row));
17438                    start..end
17439                })
17440                .collect::<Vec<_>>();
17441
17442            self.unfold_ranges(&ranges, true, true, cx);
17443        } else {
17444            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17445            let buffer_ids = self
17446                .selections
17447                .disjoint_anchor_ranges()
17448                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17449                .collect::<HashSet<_>>();
17450            for buffer_id in buffer_ids {
17451                self.unfold_buffer(buffer_id, cx);
17452            }
17453        }
17454    }
17455
17456    pub fn unfold_recursive(
17457        &mut self,
17458        _: &UnfoldRecursive,
17459        _window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17463        let selections = self.selections.all::<Point>(cx);
17464        let ranges = selections
17465            .iter()
17466            .map(|s| {
17467                let mut range = s.display_range(&display_map).sorted();
17468                *range.start.column_mut() = 0;
17469                *range.end.column_mut() = display_map.line_len(range.end.row());
17470                let start = range.start.to_point(&display_map);
17471                let end = range.end.to_point(&display_map);
17472                start..end
17473            })
17474            .collect::<Vec<_>>();
17475
17476        self.unfold_ranges(&ranges, true, true, cx);
17477    }
17478
17479    pub fn unfold_at(
17480        &mut self,
17481        buffer_row: MultiBufferRow,
17482        _window: &mut Window,
17483        cx: &mut Context<Self>,
17484    ) {
17485        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17486
17487        let intersection_range = Point::new(buffer_row.0, 0)
17488            ..Point::new(
17489                buffer_row.0,
17490                display_map.buffer_snapshot.line_len(buffer_row),
17491            );
17492
17493        let autoscroll = self
17494            .selections
17495            .all::<Point>(cx)
17496            .iter()
17497            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17498
17499        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17500    }
17501
17502    pub fn unfold_all(
17503        &mut self,
17504        _: &actions::UnfoldAll,
17505        _window: &mut Window,
17506        cx: &mut Context<Self>,
17507    ) {
17508        if self.buffer.read(cx).is_singleton() {
17509            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17510            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17511        } else {
17512            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17513                editor
17514                    .update(cx, |editor, cx| {
17515                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17516                            editor.unfold_buffer(buffer_id, cx);
17517                        }
17518                    })
17519                    .ok();
17520            });
17521        }
17522    }
17523
17524    pub fn fold_selected_ranges(
17525        &mut self,
17526        _: &FoldSelectedRanges,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) {
17530        let selections = self.selections.all_adjusted(cx);
17531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17532        let ranges = selections
17533            .into_iter()
17534            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17535            .collect::<Vec<_>>();
17536        self.fold_creases(ranges, true, window, cx);
17537    }
17538
17539    pub fn fold_ranges<T: ToOffset + Clone>(
17540        &mut self,
17541        ranges: Vec<Range<T>>,
17542        auto_scroll: bool,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17547        let ranges = ranges
17548            .into_iter()
17549            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17550            .collect::<Vec<_>>();
17551        self.fold_creases(ranges, auto_scroll, window, cx);
17552    }
17553
17554    pub fn fold_creases<T: ToOffset + Clone>(
17555        &mut self,
17556        creases: Vec<Crease<T>>,
17557        auto_scroll: bool,
17558        _window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) {
17561        if creases.is_empty() {
17562            return;
17563        }
17564
17565        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17566
17567        if auto_scroll {
17568            self.request_autoscroll(Autoscroll::fit(), cx);
17569        }
17570
17571        cx.notify();
17572
17573        self.scrollbar_marker_state.dirty = true;
17574        self.folds_did_change(cx);
17575    }
17576
17577    /// Removes any folds whose ranges intersect any of the given ranges.
17578    pub fn unfold_ranges<T: ToOffset + Clone>(
17579        &mut self,
17580        ranges: &[Range<T>],
17581        inclusive: bool,
17582        auto_scroll: bool,
17583        cx: &mut Context<Self>,
17584    ) {
17585        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17586            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17587        });
17588        self.folds_did_change(cx);
17589    }
17590
17591    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17592        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17593            return;
17594        }
17595        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17596        self.display_map.update(cx, |display_map, cx| {
17597            display_map.fold_buffers([buffer_id], cx)
17598        });
17599        cx.emit(EditorEvent::BufferFoldToggled {
17600            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17601            folded: true,
17602        });
17603        cx.notify();
17604    }
17605
17606    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17607        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17608            return;
17609        }
17610        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17611        self.display_map.update(cx, |display_map, cx| {
17612            display_map.unfold_buffers([buffer_id], cx);
17613        });
17614        cx.emit(EditorEvent::BufferFoldToggled {
17615            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17616            folded: false,
17617        });
17618        cx.notify();
17619    }
17620
17621    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17622        self.display_map.read(cx).is_buffer_folded(buffer)
17623    }
17624
17625    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17626        self.display_map.read(cx).folded_buffers()
17627    }
17628
17629    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17630        self.display_map.update(cx, |display_map, cx| {
17631            display_map.disable_header_for_buffer(buffer_id, cx);
17632        });
17633        cx.notify();
17634    }
17635
17636    /// Removes any folds with the given ranges.
17637    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17638        &mut self,
17639        ranges: &[Range<T>],
17640        type_id: TypeId,
17641        auto_scroll: bool,
17642        cx: &mut Context<Self>,
17643    ) {
17644        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17645            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17646        });
17647        self.folds_did_change(cx);
17648    }
17649
17650    fn remove_folds_with<T: ToOffset + Clone>(
17651        &mut self,
17652        ranges: &[Range<T>],
17653        auto_scroll: bool,
17654        cx: &mut Context<Self>,
17655        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17656    ) {
17657        if ranges.is_empty() {
17658            return;
17659        }
17660
17661        let mut buffers_affected = HashSet::default();
17662        let multi_buffer = self.buffer().read(cx);
17663        for range in ranges {
17664            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17665                buffers_affected.insert(buffer.read(cx).remote_id());
17666            };
17667        }
17668
17669        self.display_map.update(cx, update);
17670
17671        if auto_scroll {
17672            self.request_autoscroll(Autoscroll::fit(), cx);
17673        }
17674
17675        cx.notify();
17676        self.scrollbar_marker_state.dirty = true;
17677        self.active_indent_guides_state.dirty = true;
17678    }
17679
17680    pub fn update_renderer_widths(
17681        &mut self,
17682        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17683        cx: &mut Context<Self>,
17684    ) -> bool {
17685        self.display_map
17686            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17687    }
17688
17689    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17690        self.display_map.read(cx).fold_placeholder.clone()
17691    }
17692
17693    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17694        self.buffer.update(cx, |buffer, cx| {
17695            buffer.set_all_diff_hunks_expanded(cx);
17696        });
17697    }
17698
17699    pub fn expand_all_diff_hunks(
17700        &mut self,
17701        _: &ExpandAllDiffHunks,
17702        _window: &mut Window,
17703        cx: &mut Context<Self>,
17704    ) {
17705        self.buffer.update(cx, |buffer, cx| {
17706            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17707        });
17708    }
17709
17710    pub fn toggle_selected_diff_hunks(
17711        &mut self,
17712        _: &ToggleSelectedDiffHunks,
17713        _window: &mut Window,
17714        cx: &mut Context<Self>,
17715    ) {
17716        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17717        self.toggle_diff_hunks_in_ranges(ranges, cx);
17718    }
17719
17720    pub fn diff_hunks_in_ranges<'a>(
17721        &'a self,
17722        ranges: &'a [Range<Anchor>],
17723        buffer: &'a MultiBufferSnapshot,
17724    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17725        ranges.iter().flat_map(move |range| {
17726            let end_excerpt_id = range.end.excerpt_id;
17727            let range = range.to_point(buffer);
17728            let mut peek_end = range.end;
17729            if range.end.row < buffer.max_row().0 {
17730                peek_end = Point::new(range.end.row + 1, 0);
17731            }
17732            buffer
17733                .diff_hunks_in_range(range.start..peek_end)
17734                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17735        })
17736    }
17737
17738    pub fn has_stageable_diff_hunks_in_ranges(
17739        &self,
17740        ranges: &[Range<Anchor>],
17741        snapshot: &MultiBufferSnapshot,
17742    ) -> bool {
17743        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17744        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17745    }
17746
17747    pub fn toggle_staged_selected_diff_hunks(
17748        &mut self,
17749        _: &::git::ToggleStaged,
17750        _: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) {
17753        let snapshot = self.buffer.read(cx).snapshot(cx);
17754        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17755        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17756        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17757    }
17758
17759    pub fn set_render_diff_hunk_controls(
17760        &mut self,
17761        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17762        cx: &mut Context<Self>,
17763    ) {
17764        self.render_diff_hunk_controls = render_diff_hunk_controls;
17765        cx.notify();
17766    }
17767
17768    pub fn stage_and_next(
17769        &mut self,
17770        _: &::git::StageAndNext,
17771        window: &mut Window,
17772        cx: &mut Context<Self>,
17773    ) {
17774        self.do_stage_or_unstage_and_next(true, window, cx);
17775    }
17776
17777    pub fn unstage_and_next(
17778        &mut self,
17779        _: &::git::UnstageAndNext,
17780        window: &mut Window,
17781        cx: &mut Context<Self>,
17782    ) {
17783        self.do_stage_or_unstage_and_next(false, window, cx);
17784    }
17785
17786    pub fn stage_or_unstage_diff_hunks(
17787        &mut self,
17788        stage: bool,
17789        ranges: Vec<Range<Anchor>>,
17790        cx: &mut Context<Self>,
17791    ) {
17792        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17793        cx.spawn(async move |this, cx| {
17794            task.await?;
17795            this.update(cx, |this, cx| {
17796                let snapshot = this.buffer.read(cx).snapshot(cx);
17797                let chunk_by = this
17798                    .diff_hunks_in_ranges(&ranges, &snapshot)
17799                    .chunk_by(|hunk| hunk.buffer_id);
17800                for (buffer_id, hunks) in &chunk_by {
17801                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17802                }
17803            })
17804        })
17805        .detach_and_log_err(cx);
17806    }
17807
17808    fn save_buffers_for_ranges_if_needed(
17809        &mut self,
17810        ranges: &[Range<Anchor>],
17811        cx: &mut Context<Editor>,
17812    ) -> Task<Result<()>> {
17813        let multibuffer = self.buffer.read(cx);
17814        let snapshot = multibuffer.read(cx);
17815        let buffer_ids: HashSet<_> = ranges
17816            .iter()
17817            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17818            .collect();
17819        drop(snapshot);
17820
17821        let mut buffers = HashSet::default();
17822        for buffer_id in buffer_ids {
17823            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17824                let buffer = buffer_entity.read(cx);
17825                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17826                {
17827                    buffers.insert(buffer_entity);
17828                }
17829            }
17830        }
17831
17832        if let Some(project) = &self.project {
17833            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17834        } else {
17835            Task::ready(Ok(()))
17836        }
17837    }
17838
17839    fn do_stage_or_unstage_and_next(
17840        &mut self,
17841        stage: bool,
17842        window: &mut Window,
17843        cx: &mut Context<Self>,
17844    ) {
17845        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17846
17847        if ranges.iter().any(|range| range.start != range.end) {
17848            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17849            return;
17850        }
17851
17852        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17853        let snapshot = self.snapshot(window, cx);
17854        let position = self.selections.newest::<Point>(cx).head();
17855        let mut row = snapshot
17856            .buffer_snapshot
17857            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17858            .find(|hunk| hunk.row_range.start.0 > position.row)
17859            .map(|hunk| hunk.row_range.start);
17860
17861        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17862        // Outside of the project diff editor, wrap around to the beginning.
17863        if !all_diff_hunks_expanded {
17864            row = row.or_else(|| {
17865                snapshot
17866                    .buffer_snapshot
17867                    .diff_hunks_in_range(Point::zero()..position)
17868                    .find(|hunk| hunk.row_range.end.0 < position.row)
17869                    .map(|hunk| hunk.row_range.start)
17870            });
17871        }
17872
17873        if let Some(row) = row {
17874            let destination = Point::new(row.0, 0);
17875            let autoscroll = Autoscroll::center();
17876
17877            self.unfold_ranges(&[destination..destination], false, false, cx);
17878            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17879                s.select_ranges([destination..destination]);
17880            });
17881        }
17882    }
17883
17884    fn do_stage_or_unstage(
17885        &self,
17886        stage: bool,
17887        buffer_id: BufferId,
17888        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17889        cx: &mut App,
17890    ) -> Option<()> {
17891        let project = self.project.as_ref()?;
17892        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17893        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17894        let buffer_snapshot = buffer.read(cx).snapshot();
17895        let file_exists = buffer_snapshot
17896            .file()
17897            .is_some_and(|file| file.disk_state().exists());
17898        diff.update(cx, |diff, cx| {
17899            diff.stage_or_unstage_hunks(
17900                stage,
17901                &hunks
17902                    .map(|hunk| buffer_diff::DiffHunk {
17903                        buffer_range: hunk.buffer_range,
17904                        diff_base_byte_range: hunk.diff_base_byte_range,
17905                        secondary_status: hunk.secondary_status,
17906                        range: Point::zero()..Point::zero(), // unused
17907                    })
17908                    .collect::<Vec<_>>(),
17909                &buffer_snapshot,
17910                file_exists,
17911                cx,
17912            )
17913        });
17914        None
17915    }
17916
17917    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17918        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17919        self.buffer
17920            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17921    }
17922
17923    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17924        self.buffer.update(cx, |buffer, cx| {
17925            let ranges = vec![Anchor::min()..Anchor::max()];
17926            if !buffer.all_diff_hunks_expanded()
17927                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17928            {
17929                buffer.collapse_diff_hunks(ranges, cx);
17930                true
17931            } else {
17932                false
17933            }
17934        })
17935    }
17936
17937    fn toggle_diff_hunks_in_ranges(
17938        &mut self,
17939        ranges: Vec<Range<Anchor>>,
17940        cx: &mut Context<Editor>,
17941    ) {
17942        self.buffer.update(cx, |buffer, cx| {
17943            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17944            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17945        })
17946    }
17947
17948    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17949        self.buffer.update(cx, |buffer, cx| {
17950            let snapshot = buffer.snapshot(cx);
17951            let excerpt_id = range.end.excerpt_id;
17952            let point_range = range.to_point(&snapshot);
17953            let expand = !buffer.single_hunk_is_expanded(range, cx);
17954            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17955        })
17956    }
17957
17958    pub(crate) fn apply_all_diff_hunks(
17959        &mut self,
17960        _: &ApplyAllDiffHunks,
17961        window: &mut Window,
17962        cx: &mut Context<Self>,
17963    ) {
17964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17965
17966        let buffers = self.buffer.read(cx).all_buffers();
17967        for branch_buffer in buffers {
17968            branch_buffer.update(cx, |branch_buffer, cx| {
17969                branch_buffer.merge_into_base(Vec::new(), cx);
17970            });
17971        }
17972
17973        if let Some(project) = self.project.clone() {
17974            self.save(
17975                SaveOptions {
17976                    format: true,
17977                    autosave: false,
17978                },
17979                project,
17980                window,
17981                cx,
17982            )
17983            .detach_and_log_err(cx);
17984        }
17985    }
17986
17987    pub(crate) fn apply_selected_diff_hunks(
17988        &mut self,
17989        _: &ApplyDiffHunk,
17990        window: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) {
17993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17994        let snapshot = self.snapshot(window, cx);
17995        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17996        let mut ranges_by_buffer = HashMap::default();
17997        self.transact(window, cx, |editor, _window, cx| {
17998            for hunk in hunks {
17999                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18000                    ranges_by_buffer
18001                        .entry(buffer.clone())
18002                        .or_insert_with(Vec::new)
18003                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18004                }
18005            }
18006
18007            for (buffer, ranges) in ranges_by_buffer {
18008                buffer.update(cx, |buffer, cx| {
18009                    buffer.merge_into_base(ranges, cx);
18010                });
18011            }
18012        });
18013
18014        if let Some(project) = self.project.clone() {
18015            self.save(
18016                SaveOptions {
18017                    format: true,
18018                    autosave: false,
18019                },
18020                project,
18021                window,
18022                cx,
18023            )
18024            .detach_and_log_err(cx);
18025        }
18026    }
18027
18028    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18029        if hovered != self.gutter_hovered {
18030            self.gutter_hovered = hovered;
18031            cx.notify();
18032        }
18033    }
18034
18035    pub fn insert_blocks(
18036        &mut self,
18037        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18038        autoscroll: Option<Autoscroll>,
18039        cx: &mut Context<Self>,
18040    ) -> Vec<CustomBlockId> {
18041        let blocks = self
18042            .display_map
18043            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18044        if let Some(autoscroll) = autoscroll {
18045            self.request_autoscroll(autoscroll, cx);
18046        }
18047        cx.notify();
18048        blocks
18049    }
18050
18051    pub fn resize_blocks(
18052        &mut self,
18053        heights: HashMap<CustomBlockId, u32>,
18054        autoscroll: Option<Autoscroll>,
18055        cx: &mut Context<Self>,
18056    ) {
18057        self.display_map
18058            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18059        if let Some(autoscroll) = autoscroll {
18060            self.request_autoscroll(autoscroll, cx);
18061        }
18062        cx.notify();
18063    }
18064
18065    pub fn replace_blocks(
18066        &mut self,
18067        renderers: HashMap<CustomBlockId, RenderBlock>,
18068        autoscroll: Option<Autoscroll>,
18069        cx: &mut Context<Self>,
18070    ) {
18071        self.display_map
18072            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18073        if let Some(autoscroll) = autoscroll {
18074            self.request_autoscroll(autoscroll, cx);
18075        }
18076        cx.notify();
18077    }
18078
18079    pub fn remove_blocks(
18080        &mut self,
18081        block_ids: HashSet<CustomBlockId>,
18082        autoscroll: Option<Autoscroll>,
18083        cx: &mut Context<Self>,
18084    ) {
18085        self.display_map.update(cx, |display_map, cx| {
18086            display_map.remove_blocks(block_ids, cx)
18087        });
18088        if let Some(autoscroll) = autoscroll {
18089            self.request_autoscroll(autoscroll, cx);
18090        }
18091        cx.notify();
18092    }
18093
18094    pub fn row_for_block(
18095        &self,
18096        block_id: CustomBlockId,
18097        cx: &mut Context<Self>,
18098    ) -> Option<DisplayRow> {
18099        self.display_map
18100            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18101    }
18102
18103    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18104        self.focused_block = Some(focused_block);
18105    }
18106
18107    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18108        self.focused_block.take()
18109    }
18110
18111    pub fn insert_creases(
18112        &mut self,
18113        creases: impl IntoIterator<Item = Crease<Anchor>>,
18114        cx: &mut Context<Self>,
18115    ) -> Vec<CreaseId> {
18116        self.display_map
18117            .update(cx, |map, cx| map.insert_creases(creases, cx))
18118    }
18119
18120    pub fn remove_creases(
18121        &mut self,
18122        ids: impl IntoIterator<Item = CreaseId>,
18123        cx: &mut Context<Self>,
18124    ) -> Vec<(CreaseId, Range<Anchor>)> {
18125        self.display_map
18126            .update(cx, |map, cx| map.remove_creases(ids, cx))
18127    }
18128
18129    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18130        self.display_map
18131            .update(cx, |map, cx| map.snapshot(cx))
18132            .longest_row()
18133    }
18134
18135    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18136        self.display_map
18137            .update(cx, |map, cx| map.snapshot(cx))
18138            .max_point()
18139    }
18140
18141    pub fn text(&self, cx: &App) -> String {
18142        self.buffer.read(cx).read(cx).text()
18143    }
18144
18145    pub fn is_empty(&self, cx: &App) -> bool {
18146        self.buffer.read(cx).read(cx).is_empty()
18147    }
18148
18149    pub fn text_option(&self, cx: &App) -> Option<String> {
18150        let text = self.text(cx);
18151        let text = text.trim();
18152
18153        if text.is_empty() {
18154            return None;
18155        }
18156
18157        Some(text.to_string())
18158    }
18159
18160    pub fn set_text(
18161        &mut self,
18162        text: impl Into<Arc<str>>,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        self.transact(window, cx, |this, _, cx| {
18167            this.buffer
18168                .read(cx)
18169                .as_singleton()
18170                .expect("you can only call set_text on editors for singleton buffers")
18171                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18172        });
18173    }
18174
18175    pub fn display_text(&self, cx: &mut App) -> String {
18176        self.display_map
18177            .update(cx, |map, cx| map.snapshot(cx))
18178            .text()
18179    }
18180
18181    fn create_minimap(
18182        &self,
18183        minimap_settings: MinimapSettings,
18184        window: &mut Window,
18185        cx: &mut Context<Self>,
18186    ) -> Option<Entity<Self>> {
18187        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18188            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18189    }
18190
18191    fn initialize_new_minimap(
18192        &self,
18193        minimap_settings: MinimapSettings,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) -> Entity<Self> {
18197        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18198
18199        let mut minimap = Editor::new_internal(
18200            EditorMode::Minimap {
18201                parent: cx.weak_entity(),
18202            },
18203            self.buffer.clone(),
18204            None,
18205            Some(self.display_map.clone()),
18206            window,
18207            cx,
18208        );
18209        minimap.scroll_manager.clone_state(&self.scroll_manager);
18210        minimap.set_text_style_refinement(TextStyleRefinement {
18211            font_size: Some(MINIMAP_FONT_SIZE),
18212            font_weight: Some(MINIMAP_FONT_WEIGHT),
18213            ..Default::default()
18214        });
18215        minimap.update_minimap_configuration(minimap_settings, cx);
18216        cx.new(|_| minimap)
18217    }
18218
18219    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18220        let current_line_highlight = minimap_settings
18221            .current_line_highlight
18222            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18223        self.set_current_line_highlight(Some(current_line_highlight));
18224    }
18225
18226    pub fn minimap(&self) -> Option<&Entity<Self>> {
18227        self.minimap
18228            .as_ref()
18229            .filter(|_| self.minimap_visibility.visible())
18230    }
18231
18232    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18233        let mut wrap_guides = smallvec![];
18234
18235        if self.show_wrap_guides == Some(false) {
18236            return wrap_guides;
18237        }
18238
18239        let settings = self.buffer.read(cx).language_settings(cx);
18240        if settings.show_wrap_guides {
18241            match self.soft_wrap_mode(cx) {
18242                SoftWrap::Column(soft_wrap) => {
18243                    wrap_guides.push((soft_wrap as usize, true));
18244                }
18245                SoftWrap::Bounded(soft_wrap) => {
18246                    wrap_guides.push((soft_wrap as usize, true));
18247                }
18248                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18249            }
18250            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18251        }
18252
18253        wrap_guides
18254    }
18255
18256    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18257        let settings = self.buffer.read(cx).language_settings(cx);
18258        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18259        match mode {
18260            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18261                SoftWrap::None
18262            }
18263            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18264            language_settings::SoftWrap::PreferredLineLength => {
18265                SoftWrap::Column(settings.preferred_line_length)
18266            }
18267            language_settings::SoftWrap::Bounded => {
18268                SoftWrap::Bounded(settings.preferred_line_length)
18269            }
18270        }
18271    }
18272
18273    pub fn set_soft_wrap_mode(
18274        &mut self,
18275        mode: language_settings::SoftWrap,
18276
18277        cx: &mut Context<Self>,
18278    ) {
18279        self.soft_wrap_mode_override = Some(mode);
18280        cx.notify();
18281    }
18282
18283    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18284        self.hard_wrap = hard_wrap;
18285        cx.notify();
18286    }
18287
18288    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18289        self.text_style_refinement = Some(style);
18290    }
18291
18292    /// called by the Element so we know what style we were most recently rendered with.
18293    pub(crate) fn set_style(
18294        &mut self,
18295        style: EditorStyle,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        // We intentionally do not inform the display map about the minimap style
18300        // so that wrapping is not recalculated and stays consistent for the editor
18301        // and its linked minimap.
18302        if !self.mode.is_minimap() {
18303            let rem_size = window.rem_size();
18304            self.display_map.update(cx, |map, cx| {
18305                map.set_font(
18306                    style.text.font(),
18307                    style.text.font_size.to_pixels(rem_size),
18308                    cx,
18309                )
18310            });
18311        }
18312        self.style = Some(style);
18313    }
18314
18315    pub fn style(&self) -> Option<&EditorStyle> {
18316        self.style.as_ref()
18317    }
18318
18319    // Called by the element. This method is not designed to be called outside of the editor
18320    // element's layout code because it does not notify when rewrapping is computed synchronously.
18321    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18322        self.display_map
18323            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18324    }
18325
18326    pub fn set_soft_wrap(&mut self) {
18327        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18328    }
18329
18330    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18331        if self.soft_wrap_mode_override.is_some() {
18332            self.soft_wrap_mode_override.take();
18333        } else {
18334            let soft_wrap = match self.soft_wrap_mode(cx) {
18335                SoftWrap::GitDiff => return,
18336                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18337                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18338                    language_settings::SoftWrap::None
18339                }
18340            };
18341            self.soft_wrap_mode_override = Some(soft_wrap);
18342        }
18343        cx.notify();
18344    }
18345
18346    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18347        let Some(workspace) = self.workspace() else {
18348            return;
18349        };
18350        let fs = workspace.read(cx).app_state().fs.clone();
18351        let current_show = TabBarSettings::get_global(cx).show;
18352        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18353            setting.show = Some(!current_show);
18354        });
18355    }
18356
18357    pub fn toggle_indent_guides(
18358        &mut self,
18359        _: &ToggleIndentGuides,
18360        _: &mut Window,
18361        cx: &mut Context<Self>,
18362    ) {
18363        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18364            self.buffer
18365                .read(cx)
18366                .language_settings(cx)
18367                .indent_guides
18368                .enabled
18369        });
18370        self.show_indent_guides = Some(!currently_enabled);
18371        cx.notify();
18372    }
18373
18374    fn should_show_indent_guides(&self) -> Option<bool> {
18375        self.show_indent_guides
18376    }
18377
18378    pub fn toggle_line_numbers(
18379        &mut self,
18380        _: &ToggleLineNumbers,
18381        _: &mut Window,
18382        cx: &mut Context<Self>,
18383    ) {
18384        let mut editor_settings = EditorSettings::get_global(cx).clone();
18385        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18386        EditorSettings::override_global(editor_settings, cx);
18387    }
18388
18389    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18390        if let Some(show_line_numbers) = self.show_line_numbers {
18391            return show_line_numbers;
18392        }
18393        EditorSettings::get_global(cx).gutter.line_numbers
18394    }
18395
18396    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18397        self.use_relative_line_numbers
18398            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18399    }
18400
18401    pub fn toggle_relative_line_numbers(
18402        &mut self,
18403        _: &ToggleRelativeLineNumbers,
18404        _: &mut Window,
18405        cx: &mut Context<Self>,
18406    ) {
18407        let is_relative = self.should_use_relative_line_numbers(cx);
18408        self.set_relative_line_number(Some(!is_relative), cx)
18409    }
18410
18411    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18412        self.use_relative_line_numbers = is_relative;
18413        cx.notify();
18414    }
18415
18416    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18417        self.show_gutter = show_gutter;
18418        cx.notify();
18419    }
18420
18421    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18422        self.show_scrollbars = ScrollbarAxes {
18423            horizontal: show,
18424            vertical: show,
18425        };
18426        cx.notify();
18427    }
18428
18429    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18430        self.show_scrollbars.vertical = show;
18431        cx.notify();
18432    }
18433
18434    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18435        self.show_scrollbars.horizontal = show;
18436        cx.notify();
18437    }
18438
18439    pub fn set_minimap_visibility(
18440        &mut self,
18441        minimap_visibility: MinimapVisibility,
18442        window: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) {
18445        if self.minimap_visibility != minimap_visibility {
18446            if minimap_visibility.visible() && self.minimap.is_none() {
18447                let minimap_settings = EditorSettings::get_global(cx).minimap;
18448                self.minimap =
18449                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18450            }
18451            self.minimap_visibility = minimap_visibility;
18452            cx.notify();
18453        }
18454    }
18455
18456    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18457        self.set_show_scrollbars(false, cx);
18458        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18459    }
18460
18461    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18462        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18463    }
18464
18465    /// Normally the text in full mode and auto height editors is padded on the
18466    /// left side by roughly half a character width for improved hit testing.
18467    ///
18468    /// Use this method to disable this for cases where this is not wanted (e.g.
18469    /// if you want to align the editor text with some other text above or below)
18470    /// or if you want to add this padding to single-line editors.
18471    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18472        self.offset_content = offset_content;
18473        cx.notify();
18474    }
18475
18476    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18477        self.show_line_numbers = Some(show_line_numbers);
18478        cx.notify();
18479    }
18480
18481    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18482        self.disable_expand_excerpt_buttons = true;
18483        cx.notify();
18484    }
18485
18486    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18487        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18488        cx.notify();
18489    }
18490
18491    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18492        self.show_code_actions = Some(show_code_actions);
18493        cx.notify();
18494    }
18495
18496    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18497        self.show_runnables = Some(show_runnables);
18498        cx.notify();
18499    }
18500
18501    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18502        self.show_breakpoints = Some(show_breakpoints);
18503        cx.notify();
18504    }
18505
18506    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18507        if self.display_map.read(cx).masked != masked {
18508            self.display_map.update(cx, |map, _| map.masked = masked);
18509        }
18510        cx.notify()
18511    }
18512
18513    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18514        self.show_wrap_guides = Some(show_wrap_guides);
18515        cx.notify();
18516    }
18517
18518    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18519        self.show_indent_guides = Some(show_indent_guides);
18520        cx.notify();
18521    }
18522
18523    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18524        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18525            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18526                if let Some(dir) = file.abs_path(cx).parent() {
18527                    return Some(dir.to_owned());
18528                }
18529            }
18530
18531            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18532                return Some(project_path.path.to_path_buf());
18533            }
18534        }
18535
18536        None
18537    }
18538
18539    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18540        self.active_excerpt(cx)?
18541            .1
18542            .read(cx)
18543            .file()
18544            .and_then(|f| f.as_local())
18545    }
18546
18547    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18548        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18549            let buffer = buffer.read(cx);
18550            if let Some(project_path) = buffer.project_path(cx) {
18551                let project = self.project.as_ref()?.read(cx);
18552                project.absolute_path(&project_path, cx)
18553            } else {
18554                buffer
18555                    .file()
18556                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18557            }
18558        })
18559    }
18560
18561    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18562        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18563            let project_path = buffer.read(cx).project_path(cx)?;
18564            let project = self.project.as_ref()?.read(cx);
18565            let entry = project.entry_for_path(&project_path, cx)?;
18566            let path = entry.path.to_path_buf();
18567            Some(path)
18568        })
18569    }
18570
18571    pub fn reveal_in_finder(
18572        &mut self,
18573        _: &RevealInFileManager,
18574        _window: &mut Window,
18575        cx: &mut Context<Self>,
18576    ) {
18577        if let Some(target) = self.target_file(cx) {
18578            cx.reveal_path(&target.abs_path(cx));
18579        }
18580    }
18581
18582    pub fn copy_path(
18583        &mut self,
18584        _: &zed_actions::workspace::CopyPath,
18585        _window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        if let Some(path) = self.target_file_abs_path(cx) {
18589            if let Some(path) = path.to_str() {
18590                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18591            }
18592        }
18593    }
18594
18595    pub fn copy_relative_path(
18596        &mut self,
18597        _: &zed_actions::workspace::CopyRelativePath,
18598        _window: &mut Window,
18599        cx: &mut Context<Self>,
18600    ) {
18601        if let Some(path) = self.target_file_path(cx) {
18602            if let Some(path) = path.to_str() {
18603                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18604            }
18605        }
18606    }
18607
18608    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18609        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18610            buffer.read(cx).project_path(cx)
18611        } else {
18612            None
18613        }
18614    }
18615
18616    // Returns true if the editor handled a go-to-line request
18617    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18618        maybe!({
18619            let breakpoint_store = self.breakpoint_store.as_ref()?;
18620
18621            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18622            else {
18623                self.clear_row_highlights::<ActiveDebugLine>();
18624                return None;
18625            };
18626
18627            let position = active_stack_frame.position;
18628            let buffer_id = position.buffer_id?;
18629            let snapshot = self
18630                .project
18631                .as_ref()?
18632                .read(cx)
18633                .buffer_for_id(buffer_id, cx)?
18634                .read(cx)
18635                .snapshot();
18636
18637            let mut handled = false;
18638            for (id, ExcerptRange { context, .. }) in
18639                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18640            {
18641                if context.start.cmp(&position, &snapshot).is_ge()
18642                    || context.end.cmp(&position, &snapshot).is_lt()
18643                {
18644                    continue;
18645                }
18646                let snapshot = self.buffer.read(cx).snapshot(cx);
18647                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18648
18649                handled = true;
18650                self.clear_row_highlights::<ActiveDebugLine>();
18651
18652                self.go_to_line::<ActiveDebugLine>(
18653                    multibuffer_anchor,
18654                    Some(cx.theme().colors().editor_debugger_active_line_background),
18655                    window,
18656                    cx,
18657                );
18658
18659                cx.notify();
18660            }
18661
18662            handled.then_some(())
18663        })
18664        .is_some()
18665    }
18666
18667    pub fn copy_file_name_without_extension(
18668        &mut self,
18669        _: &CopyFileNameWithoutExtension,
18670        _: &mut Window,
18671        cx: &mut Context<Self>,
18672    ) {
18673        if let Some(file) = self.target_file(cx) {
18674            if let Some(file_stem) = file.path().file_stem() {
18675                if let Some(name) = file_stem.to_str() {
18676                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18677                }
18678            }
18679        }
18680    }
18681
18682    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18683        if let Some(file) = self.target_file(cx) {
18684            if let Some(file_name) = file.path().file_name() {
18685                if let Some(name) = file_name.to_str() {
18686                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18687                }
18688            }
18689        }
18690    }
18691
18692    pub fn toggle_git_blame(
18693        &mut self,
18694        _: &::git::Blame,
18695        window: &mut Window,
18696        cx: &mut Context<Self>,
18697    ) {
18698        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18699
18700        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18701            self.start_git_blame(true, window, cx);
18702        }
18703
18704        cx.notify();
18705    }
18706
18707    pub fn toggle_git_blame_inline(
18708        &mut self,
18709        _: &ToggleGitBlameInline,
18710        window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) {
18713        self.toggle_git_blame_inline_internal(true, window, cx);
18714        cx.notify();
18715    }
18716
18717    pub fn open_git_blame_commit(
18718        &mut self,
18719        _: &OpenGitBlameCommit,
18720        window: &mut Window,
18721        cx: &mut Context<Self>,
18722    ) {
18723        self.open_git_blame_commit_internal(window, cx);
18724    }
18725
18726    fn open_git_blame_commit_internal(
18727        &mut self,
18728        window: &mut Window,
18729        cx: &mut Context<Self>,
18730    ) -> Option<()> {
18731        let blame = self.blame.as_ref()?;
18732        let snapshot = self.snapshot(window, cx);
18733        let cursor = self.selections.newest::<Point>(cx).head();
18734        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18735        let blame_entry = blame
18736            .update(cx, |blame, cx| {
18737                blame
18738                    .blame_for_rows(
18739                        &[RowInfo {
18740                            buffer_id: Some(buffer.remote_id()),
18741                            buffer_row: Some(point.row),
18742                            ..Default::default()
18743                        }],
18744                        cx,
18745                    )
18746                    .next()
18747            })
18748            .flatten()?;
18749        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18750        let repo = blame.read(cx).repository(cx)?;
18751        let workspace = self.workspace()?.downgrade();
18752        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18753        None
18754    }
18755
18756    pub fn git_blame_inline_enabled(&self) -> bool {
18757        self.git_blame_inline_enabled
18758    }
18759
18760    pub fn toggle_selection_menu(
18761        &mut self,
18762        _: &ToggleSelectionMenu,
18763        _: &mut Window,
18764        cx: &mut Context<Self>,
18765    ) {
18766        self.show_selection_menu = self
18767            .show_selection_menu
18768            .map(|show_selections_menu| !show_selections_menu)
18769            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18770
18771        cx.notify();
18772    }
18773
18774    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18775        self.show_selection_menu
18776            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18777    }
18778
18779    fn start_git_blame(
18780        &mut self,
18781        user_triggered: bool,
18782        window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        if let Some(project) = self.project.as_ref() {
18786            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18787                return;
18788            };
18789
18790            if buffer.read(cx).file().is_none() {
18791                return;
18792            }
18793
18794            let focused = self.focus_handle(cx).contains_focused(window, cx);
18795
18796            let project = project.clone();
18797            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18798            self.blame_subscription =
18799                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18800            self.blame = Some(blame);
18801        }
18802    }
18803
18804    fn toggle_git_blame_inline_internal(
18805        &mut self,
18806        user_triggered: bool,
18807        window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        if self.git_blame_inline_enabled {
18811            self.git_blame_inline_enabled = false;
18812            self.show_git_blame_inline = false;
18813            self.show_git_blame_inline_delay_task.take();
18814        } else {
18815            self.git_blame_inline_enabled = true;
18816            self.start_git_blame_inline(user_triggered, window, cx);
18817        }
18818
18819        cx.notify();
18820    }
18821
18822    fn start_git_blame_inline(
18823        &mut self,
18824        user_triggered: bool,
18825        window: &mut Window,
18826        cx: &mut Context<Self>,
18827    ) {
18828        self.start_git_blame(user_triggered, window, cx);
18829
18830        if ProjectSettings::get_global(cx)
18831            .git
18832            .inline_blame_delay()
18833            .is_some()
18834        {
18835            self.start_inline_blame_timer(window, cx);
18836        } else {
18837            self.show_git_blame_inline = true
18838        }
18839    }
18840
18841    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18842        self.blame.as_ref()
18843    }
18844
18845    pub fn show_git_blame_gutter(&self) -> bool {
18846        self.show_git_blame_gutter
18847    }
18848
18849    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18850        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18851    }
18852
18853    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18854        self.show_git_blame_inline
18855            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18856            && !self.newest_selection_head_on_empty_line(cx)
18857            && self.has_blame_entries(cx)
18858    }
18859
18860    fn has_blame_entries(&self, cx: &App) -> bool {
18861        self.blame()
18862            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18863    }
18864
18865    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18866        let cursor_anchor = self.selections.newest_anchor().head();
18867
18868        let snapshot = self.buffer.read(cx).snapshot(cx);
18869        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18870
18871        snapshot.line_len(buffer_row) == 0
18872    }
18873
18874    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18875        let buffer_and_selection = maybe!({
18876            let selection = self.selections.newest::<Point>(cx);
18877            let selection_range = selection.range();
18878
18879            let multi_buffer = self.buffer().read(cx);
18880            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18881            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18882
18883            let (buffer, range, _) = if selection.reversed {
18884                buffer_ranges.first()
18885            } else {
18886                buffer_ranges.last()
18887            }?;
18888
18889            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18890                ..text::ToPoint::to_point(&range.end, &buffer).row;
18891            Some((
18892                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18893                selection,
18894            ))
18895        });
18896
18897        let Some((buffer, selection)) = buffer_and_selection else {
18898            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18899        };
18900
18901        let Some(project) = self.project.as_ref() else {
18902            return Task::ready(Err(anyhow!("editor does not have project")));
18903        };
18904
18905        project.update(cx, |project, cx| {
18906            project.get_permalink_to_line(&buffer, selection, cx)
18907        })
18908    }
18909
18910    pub fn copy_permalink_to_line(
18911        &mut self,
18912        _: &CopyPermalinkToLine,
18913        window: &mut Window,
18914        cx: &mut Context<Self>,
18915    ) {
18916        let permalink_task = self.get_permalink_to_line(cx);
18917        let workspace = self.workspace();
18918
18919        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18920            Ok(permalink) => {
18921                cx.update(|_, cx| {
18922                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18923                })
18924                .ok();
18925            }
18926            Err(err) => {
18927                let message = format!("Failed to copy permalink: {err}");
18928
18929                anyhow::Result::<()>::Err(err).log_err();
18930
18931                if let Some(workspace) = workspace {
18932                    workspace
18933                        .update_in(cx, |workspace, _, cx| {
18934                            struct CopyPermalinkToLine;
18935
18936                            workspace.show_toast(
18937                                Toast::new(
18938                                    NotificationId::unique::<CopyPermalinkToLine>(),
18939                                    message,
18940                                ),
18941                                cx,
18942                            )
18943                        })
18944                        .ok();
18945                }
18946            }
18947        })
18948        .detach();
18949    }
18950
18951    pub fn copy_file_location(
18952        &mut self,
18953        _: &CopyFileLocation,
18954        _: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) {
18957        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18958        if let Some(file) = self.target_file(cx) {
18959            if let Some(path) = file.path().to_str() {
18960                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18961            }
18962        }
18963    }
18964
18965    pub fn open_permalink_to_line(
18966        &mut self,
18967        _: &OpenPermalinkToLine,
18968        window: &mut Window,
18969        cx: &mut Context<Self>,
18970    ) {
18971        let permalink_task = self.get_permalink_to_line(cx);
18972        let workspace = self.workspace();
18973
18974        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18975            Ok(permalink) => {
18976                cx.update(|_, cx| {
18977                    cx.open_url(permalink.as_ref());
18978                })
18979                .ok();
18980            }
18981            Err(err) => {
18982                let message = format!("Failed to open permalink: {err}");
18983
18984                anyhow::Result::<()>::Err(err).log_err();
18985
18986                if let Some(workspace) = workspace {
18987                    workspace
18988                        .update(cx, |workspace, cx| {
18989                            struct OpenPermalinkToLine;
18990
18991                            workspace.show_toast(
18992                                Toast::new(
18993                                    NotificationId::unique::<OpenPermalinkToLine>(),
18994                                    message,
18995                                ),
18996                                cx,
18997                            )
18998                        })
18999                        .ok();
19000                }
19001            }
19002        })
19003        .detach();
19004    }
19005
19006    pub fn insert_uuid_v4(
19007        &mut self,
19008        _: &InsertUuidV4,
19009        window: &mut Window,
19010        cx: &mut Context<Self>,
19011    ) {
19012        self.insert_uuid(UuidVersion::V4, window, cx);
19013    }
19014
19015    pub fn insert_uuid_v7(
19016        &mut self,
19017        _: &InsertUuidV7,
19018        window: &mut Window,
19019        cx: &mut Context<Self>,
19020    ) {
19021        self.insert_uuid(UuidVersion::V7, window, cx);
19022    }
19023
19024    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19026        self.transact(window, cx, |this, window, cx| {
19027            let edits = this
19028                .selections
19029                .all::<Point>(cx)
19030                .into_iter()
19031                .map(|selection| {
19032                    let uuid = match version {
19033                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19034                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19035                    };
19036
19037                    (selection.range(), uuid.to_string())
19038                });
19039            this.edit(edits, cx);
19040            this.refresh_inline_completion(true, false, window, cx);
19041        });
19042    }
19043
19044    pub fn open_selections_in_multibuffer(
19045        &mut self,
19046        _: &OpenSelectionsInMultibuffer,
19047        window: &mut Window,
19048        cx: &mut Context<Self>,
19049    ) {
19050        let multibuffer = self.buffer.read(cx);
19051
19052        let Some(buffer) = multibuffer.as_singleton() else {
19053            return;
19054        };
19055
19056        let Some(workspace) = self.workspace() else {
19057            return;
19058        };
19059
19060        let title = multibuffer.title(cx).to_string();
19061
19062        let locations = self
19063            .selections
19064            .all_anchors(cx)
19065            .into_iter()
19066            .map(|selection| Location {
19067                buffer: buffer.clone(),
19068                range: selection.start.text_anchor..selection.end.text_anchor,
19069            })
19070            .collect::<Vec<_>>();
19071
19072        cx.spawn_in(window, async move |_, cx| {
19073            workspace.update_in(cx, |workspace, window, cx| {
19074                Self::open_locations_in_multibuffer(
19075                    workspace,
19076                    locations,
19077                    format!("Selections for '{title}'"),
19078                    false,
19079                    MultibufferSelectionMode::All,
19080                    window,
19081                    cx,
19082                );
19083            })
19084        })
19085        .detach();
19086    }
19087
19088    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19089    /// last highlight added will be used.
19090    ///
19091    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19092    pub fn highlight_rows<T: 'static>(
19093        &mut self,
19094        range: Range<Anchor>,
19095        color: Hsla,
19096        options: RowHighlightOptions,
19097        cx: &mut Context<Self>,
19098    ) {
19099        let snapshot = self.buffer().read(cx).snapshot(cx);
19100        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19101        let ix = row_highlights.binary_search_by(|highlight| {
19102            Ordering::Equal
19103                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19104                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19105        });
19106
19107        if let Err(mut ix) = ix {
19108            let index = post_inc(&mut self.highlight_order);
19109
19110            // If this range intersects with the preceding highlight, then merge it with
19111            // the preceding highlight. Otherwise insert a new highlight.
19112            let mut merged = false;
19113            if ix > 0 {
19114                let prev_highlight = &mut row_highlights[ix - 1];
19115                if prev_highlight
19116                    .range
19117                    .end
19118                    .cmp(&range.start, &snapshot)
19119                    .is_ge()
19120                {
19121                    ix -= 1;
19122                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19123                        prev_highlight.range.end = range.end;
19124                    }
19125                    merged = true;
19126                    prev_highlight.index = index;
19127                    prev_highlight.color = color;
19128                    prev_highlight.options = options;
19129                }
19130            }
19131
19132            if !merged {
19133                row_highlights.insert(
19134                    ix,
19135                    RowHighlight {
19136                        range: range.clone(),
19137                        index,
19138                        color,
19139                        options,
19140                        type_id: TypeId::of::<T>(),
19141                    },
19142                );
19143            }
19144
19145            // If any of the following highlights intersect with this one, merge them.
19146            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19147                let highlight = &row_highlights[ix];
19148                if next_highlight
19149                    .range
19150                    .start
19151                    .cmp(&highlight.range.end, &snapshot)
19152                    .is_le()
19153                {
19154                    if next_highlight
19155                        .range
19156                        .end
19157                        .cmp(&highlight.range.end, &snapshot)
19158                        .is_gt()
19159                    {
19160                        row_highlights[ix].range.end = next_highlight.range.end;
19161                    }
19162                    row_highlights.remove(ix + 1);
19163                } else {
19164                    break;
19165                }
19166            }
19167        }
19168    }
19169
19170    /// Remove any highlighted row ranges of the given type that intersect the
19171    /// given ranges.
19172    pub fn remove_highlighted_rows<T: 'static>(
19173        &mut self,
19174        ranges_to_remove: Vec<Range<Anchor>>,
19175        cx: &mut Context<Self>,
19176    ) {
19177        let snapshot = self.buffer().read(cx).snapshot(cx);
19178        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19179        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19180        row_highlights.retain(|highlight| {
19181            while let Some(range_to_remove) = ranges_to_remove.peek() {
19182                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19183                    Ordering::Less | Ordering::Equal => {
19184                        ranges_to_remove.next();
19185                    }
19186                    Ordering::Greater => {
19187                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19188                            Ordering::Less | Ordering::Equal => {
19189                                return false;
19190                            }
19191                            Ordering::Greater => break,
19192                        }
19193                    }
19194                }
19195            }
19196
19197            true
19198        })
19199    }
19200
19201    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19202    pub fn clear_row_highlights<T: 'static>(&mut self) {
19203        self.highlighted_rows.remove(&TypeId::of::<T>());
19204    }
19205
19206    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19207    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19208        self.highlighted_rows
19209            .get(&TypeId::of::<T>())
19210            .map_or(&[] as &[_], |vec| vec.as_slice())
19211            .iter()
19212            .map(|highlight| (highlight.range.clone(), highlight.color))
19213    }
19214
19215    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19216    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19217    /// Allows to ignore certain kinds of highlights.
19218    pub fn highlighted_display_rows(
19219        &self,
19220        window: &mut Window,
19221        cx: &mut App,
19222    ) -> BTreeMap<DisplayRow, LineHighlight> {
19223        let snapshot = self.snapshot(window, cx);
19224        let mut used_highlight_orders = HashMap::default();
19225        self.highlighted_rows
19226            .iter()
19227            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19228            .fold(
19229                BTreeMap::<DisplayRow, LineHighlight>::new(),
19230                |mut unique_rows, highlight| {
19231                    let start = highlight.range.start.to_display_point(&snapshot);
19232                    let end = highlight.range.end.to_display_point(&snapshot);
19233                    let start_row = start.row().0;
19234                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19235                        && end.column() == 0
19236                    {
19237                        end.row().0.saturating_sub(1)
19238                    } else {
19239                        end.row().0
19240                    };
19241                    for row in start_row..=end_row {
19242                        let used_index =
19243                            used_highlight_orders.entry(row).or_insert(highlight.index);
19244                        if highlight.index >= *used_index {
19245                            *used_index = highlight.index;
19246                            unique_rows.insert(
19247                                DisplayRow(row),
19248                                LineHighlight {
19249                                    include_gutter: highlight.options.include_gutter,
19250                                    border: None,
19251                                    background: highlight.color.into(),
19252                                    type_id: Some(highlight.type_id),
19253                                },
19254                            );
19255                        }
19256                    }
19257                    unique_rows
19258                },
19259            )
19260    }
19261
19262    pub fn highlighted_display_row_for_autoscroll(
19263        &self,
19264        snapshot: &DisplaySnapshot,
19265    ) -> Option<DisplayRow> {
19266        self.highlighted_rows
19267            .values()
19268            .flat_map(|highlighted_rows| highlighted_rows.iter())
19269            .filter_map(|highlight| {
19270                if highlight.options.autoscroll {
19271                    Some(highlight.range.start.to_display_point(snapshot).row())
19272                } else {
19273                    None
19274                }
19275            })
19276            .min()
19277    }
19278
19279    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19280        self.highlight_background::<SearchWithinRange>(
19281            ranges,
19282            |colors| colors.colors().editor_document_highlight_read_background,
19283            cx,
19284        )
19285    }
19286
19287    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19288        self.breadcrumb_header = Some(new_header);
19289    }
19290
19291    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19292        self.clear_background_highlights::<SearchWithinRange>(cx);
19293    }
19294
19295    pub fn highlight_background<T: 'static>(
19296        &mut self,
19297        ranges: &[Range<Anchor>],
19298        color_fetcher: fn(&Theme) -> Hsla,
19299        cx: &mut Context<Self>,
19300    ) {
19301        self.background_highlights.insert(
19302            HighlightKey::Type(TypeId::of::<T>()),
19303            (color_fetcher, Arc::from(ranges)),
19304        );
19305        self.scrollbar_marker_state.dirty = true;
19306        cx.notify();
19307    }
19308
19309    pub fn highlight_background_key<T: 'static>(
19310        &mut self,
19311        key: usize,
19312        ranges: &[Range<Anchor>],
19313        color_fetcher: fn(&Theme) -> Hsla,
19314        cx: &mut Context<Self>,
19315    ) {
19316        self.background_highlights.insert(
19317            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19318            (color_fetcher, Arc::from(ranges)),
19319        );
19320        self.scrollbar_marker_state.dirty = true;
19321        cx.notify();
19322    }
19323
19324    pub fn clear_background_highlights<T: 'static>(
19325        &mut self,
19326        cx: &mut Context<Self>,
19327    ) -> Option<BackgroundHighlight> {
19328        let text_highlights = self
19329            .background_highlights
19330            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19331        if !text_highlights.1.is_empty() {
19332            self.scrollbar_marker_state.dirty = true;
19333            cx.notify();
19334        }
19335        Some(text_highlights)
19336    }
19337
19338    pub fn highlight_gutter<T: 'static>(
19339        &mut self,
19340        ranges: impl Into<Vec<Range<Anchor>>>,
19341        color_fetcher: fn(&App) -> Hsla,
19342        cx: &mut Context<Self>,
19343    ) {
19344        self.gutter_highlights
19345            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19346        cx.notify();
19347    }
19348
19349    pub fn clear_gutter_highlights<T: 'static>(
19350        &mut self,
19351        cx: &mut Context<Self>,
19352    ) -> Option<GutterHighlight> {
19353        cx.notify();
19354        self.gutter_highlights.remove(&TypeId::of::<T>())
19355    }
19356
19357    pub fn insert_gutter_highlight<T: 'static>(
19358        &mut self,
19359        range: Range<Anchor>,
19360        color_fetcher: fn(&App) -> Hsla,
19361        cx: &mut Context<Self>,
19362    ) {
19363        let snapshot = self.buffer().read(cx).snapshot(cx);
19364        let mut highlights = self
19365            .gutter_highlights
19366            .remove(&TypeId::of::<T>())
19367            .map(|(_, highlights)| highlights)
19368            .unwrap_or_default();
19369        let ix = highlights.binary_search_by(|highlight| {
19370            Ordering::Equal
19371                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19372                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19373        });
19374        if let Err(ix) = ix {
19375            highlights.insert(ix, range);
19376        }
19377        self.gutter_highlights
19378            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19379    }
19380
19381    pub fn remove_gutter_highlights<T: 'static>(
19382        &mut self,
19383        ranges_to_remove: Vec<Range<Anchor>>,
19384        cx: &mut Context<Self>,
19385    ) {
19386        let snapshot = self.buffer().read(cx).snapshot(cx);
19387        let Some((color_fetcher, mut gutter_highlights)) =
19388            self.gutter_highlights.remove(&TypeId::of::<T>())
19389        else {
19390            return;
19391        };
19392        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19393        gutter_highlights.retain(|highlight| {
19394            while let Some(range_to_remove) = ranges_to_remove.peek() {
19395                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19396                    Ordering::Less | Ordering::Equal => {
19397                        ranges_to_remove.next();
19398                    }
19399                    Ordering::Greater => {
19400                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19401                            Ordering::Less | Ordering::Equal => {
19402                                return false;
19403                            }
19404                            Ordering::Greater => break,
19405                        }
19406                    }
19407                }
19408            }
19409
19410            true
19411        });
19412        self.gutter_highlights
19413            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19414    }
19415
19416    #[cfg(feature = "test-support")]
19417    pub fn all_text_highlights(
19418        &self,
19419        window: &mut Window,
19420        cx: &mut Context<Self>,
19421    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19422        let snapshot = self.snapshot(window, cx);
19423        self.display_map.update(cx, |display_map, _| {
19424            display_map
19425                .all_text_highlights()
19426                .map(|highlight| {
19427                    let (style, ranges) = highlight.as_ref();
19428                    (
19429                        *style,
19430                        ranges
19431                            .iter()
19432                            .map(|range| range.clone().to_display_points(&snapshot))
19433                            .collect(),
19434                    )
19435                })
19436                .collect()
19437        })
19438    }
19439
19440    #[cfg(feature = "test-support")]
19441    pub fn all_text_background_highlights(
19442        &self,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19446        let snapshot = self.snapshot(window, cx);
19447        let buffer = &snapshot.buffer_snapshot;
19448        let start = buffer.anchor_before(0);
19449        let end = buffer.anchor_after(buffer.len());
19450        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19451    }
19452
19453    #[cfg(feature = "test-support")]
19454    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19455        let snapshot = self.buffer().read(cx).snapshot(cx);
19456
19457        let highlights = self
19458            .background_highlights
19459            .get(&HighlightKey::Type(TypeId::of::<
19460                items::BufferSearchHighlights,
19461            >()));
19462
19463        if let Some((_color, ranges)) = highlights {
19464            ranges
19465                .iter()
19466                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19467                .collect_vec()
19468        } else {
19469            vec![]
19470        }
19471    }
19472
19473    fn document_highlights_for_position<'a>(
19474        &'a self,
19475        position: Anchor,
19476        buffer: &'a MultiBufferSnapshot,
19477    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19478        let read_highlights = self
19479            .background_highlights
19480            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19481            .map(|h| &h.1);
19482        let write_highlights = self
19483            .background_highlights
19484            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19485            .map(|h| &h.1);
19486        let left_position = position.bias_left(buffer);
19487        let right_position = position.bias_right(buffer);
19488        read_highlights
19489            .into_iter()
19490            .chain(write_highlights)
19491            .flat_map(move |ranges| {
19492                let start_ix = match ranges.binary_search_by(|probe| {
19493                    let cmp = probe.end.cmp(&left_position, buffer);
19494                    if cmp.is_ge() {
19495                        Ordering::Greater
19496                    } else {
19497                        Ordering::Less
19498                    }
19499                }) {
19500                    Ok(i) | Err(i) => i,
19501                };
19502
19503                ranges[start_ix..]
19504                    .iter()
19505                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19506            })
19507    }
19508
19509    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19510        self.background_highlights
19511            .get(&HighlightKey::Type(TypeId::of::<T>()))
19512            .map_or(false, |(_, highlights)| !highlights.is_empty())
19513    }
19514
19515    pub fn background_highlights_in_range(
19516        &self,
19517        search_range: Range<Anchor>,
19518        display_snapshot: &DisplaySnapshot,
19519        theme: &Theme,
19520    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19521        let mut results = Vec::new();
19522        for (color_fetcher, ranges) in self.background_highlights.values() {
19523            let color = color_fetcher(theme);
19524            let start_ix = match ranges.binary_search_by(|probe| {
19525                let cmp = probe
19526                    .end
19527                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19528                if cmp.is_gt() {
19529                    Ordering::Greater
19530                } else {
19531                    Ordering::Less
19532                }
19533            }) {
19534                Ok(i) | Err(i) => i,
19535            };
19536            for range in &ranges[start_ix..] {
19537                if range
19538                    .start
19539                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19540                    .is_ge()
19541                {
19542                    break;
19543                }
19544
19545                let start = range.start.to_display_point(display_snapshot);
19546                let end = range.end.to_display_point(display_snapshot);
19547                results.push((start..end, color))
19548            }
19549        }
19550        results
19551    }
19552
19553    pub fn background_highlight_row_ranges<T: 'static>(
19554        &self,
19555        search_range: Range<Anchor>,
19556        display_snapshot: &DisplaySnapshot,
19557        count: usize,
19558    ) -> Vec<RangeInclusive<DisplayPoint>> {
19559        let mut results = Vec::new();
19560        let Some((_, ranges)) = self
19561            .background_highlights
19562            .get(&HighlightKey::Type(TypeId::of::<T>()))
19563        else {
19564            return vec![];
19565        };
19566
19567        let start_ix = match ranges.binary_search_by(|probe| {
19568            let cmp = probe
19569                .end
19570                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19571            if cmp.is_gt() {
19572                Ordering::Greater
19573            } else {
19574                Ordering::Less
19575            }
19576        }) {
19577            Ok(i) | Err(i) => i,
19578        };
19579        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19580            if let (Some(start_display), Some(end_display)) = (start, end) {
19581                results.push(
19582                    start_display.to_display_point(display_snapshot)
19583                        ..=end_display.to_display_point(display_snapshot),
19584                );
19585            }
19586        };
19587        let mut start_row: Option<Point> = None;
19588        let mut end_row: Option<Point> = None;
19589        if ranges.len() > count {
19590            return Vec::new();
19591        }
19592        for range in &ranges[start_ix..] {
19593            if range
19594                .start
19595                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19596                .is_ge()
19597            {
19598                break;
19599            }
19600            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19601            if let Some(current_row) = &end_row {
19602                if end.row == current_row.row {
19603                    continue;
19604                }
19605            }
19606            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19607            if start_row.is_none() {
19608                assert_eq!(end_row, None);
19609                start_row = Some(start);
19610                end_row = Some(end);
19611                continue;
19612            }
19613            if let Some(current_end) = end_row.as_mut() {
19614                if start.row > current_end.row + 1 {
19615                    push_region(start_row, end_row);
19616                    start_row = Some(start);
19617                    end_row = Some(end);
19618                } else {
19619                    // Merge two hunks.
19620                    *current_end = end;
19621                }
19622            } else {
19623                unreachable!();
19624            }
19625        }
19626        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19627        push_region(start_row, end_row);
19628        results
19629    }
19630
19631    pub fn gutter_highlights_in_range(
19632        &self,
19633        search_range: Range<Anchor>,
19634        display_snapshot: &DisplaySnapshot,
19635        cx: &App,
19636    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19637        let mut results = Vec::new();
19638        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19639            let color = color_fetcher(cx);
19640            let start_ix = match ranges.binary_search_by(|probe| {
19641                let cmp = probe
19642                    .end
19643                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19644                if cmp.is_gt() {
19645                    Ordering::Greater
19646                } else {
19647                    Ordering::Less
19648                }
19649            }) {
19650                Ok(i) | Err(i) => i,
19651            };
19652            for range in &ranges[start_ix..] {
19653                if range
19654                    .start
19655                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19656                    .is_ge()
19657                {
19658                    break;
19659                }
19660
19661                let start = range.start.to_display_point(display_snapshot);
19662                let end = range.end.to_display_point(display_snapshot);
19663                results.push((start..end, color))
19664            }
19665        }
19666        results
19667    }
19668
19669    /// Get the text ranges corresponding to the redaction query
19670    pub fn redacted_ranges(
19671        &self,
19672        search_range: Range<Anchor>,
19673        display_snapshot: &DisplaySnapshot,
19674        cx: &App,
19675    ) -> Vec<Range<DisplayPoint>> {
19676        display_snapshot
19677            .buffer_snapshot
19678            .redacted_ranges(search_range, |file| {
19679                if let Some(file) = file {
19680                    file.is_private()
19681                        && EditorSettings::get(
19682                            Some(SettingsLocation {
19683                                worktree_id: file.worktree_id(cx),
19684                                path: file.path().as_ref(),
19685                            }),
19686                            cx,
19687                        )
19688                        .redact_private_values
19689                } else {
19690                    false
19691                }
19692            })
19693            .map(|range| {
19694                range.start.to_display_point(display_snapshot)
19695                    ..range.end.to_display_point(display_snapshot)
19696            })
19697            .collect()
19698    }
19699
19700    pub fn highlight_text_key<T: 'static>(
19701        &mut self,
19702        key: usize,
19703        ranges: Vec<Range<Anchor>>,
19704        style: HighlightStyle,
19705        cx: &mut Context<Self>,
19706    ) {
19707        self.display_map.update(cx, |map, _| {
19708            map.highlight_text(
19709                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19710                ranges,
19711                style,
19712            );
19713        });
19714        cx.notify();
19715    }
19716
19717    pub fn highlight_text<T: 'static>(
19718        &mut self,
19719        ranges: Vec<Range<Anchor>>,
19720        style: HighlightStyle,
19721        cx: &mut Context<Self>,
19722    ) {
19723        self.display_map.update(cx, |map, _| {
19724            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19725        });
19726        cx.notify();
19727    }
19728
19729    pub(crate) fn highlight_inlays<T: 'static>(
19730        &mut self,
19731        highlights: Vec<InlayHighlight>,
19732        style: HighlightStyle,
19733        cx: &mut Context<Self>,
19734    ) {
19735        self.display_map.update(cx, |map, _| {
19736            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19737        });
19738        cx.notify();
19739    }
19740
19741    pub fn text_highlights<'a, T: 'static>(
19742        &'a self,
19743        cx: &'a App,
19744    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19745        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19746    }
19747
19748    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19749        let cleared = self
19750            .display_map
19751            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19752        if cleared {
19753            cx.notify();
19754        }
19755    }
19756
19757    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19758        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19759            && self.focus_handle.is_focused(window)
19760    }
19761
19762    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19763        self.show_cursor_when_unfocused = is_enabled;
19764        cx.notify();
19765    }
19766
19767    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19768        cx.notify();
19769    }
19770
19771    fn on_debug_session_event(
19772        &mut self,
19773        _session: Entity<Session>,
19774        event: &SessionEvent,
19775        cx: &mut Context<Self>,
19776    ) {
19777        match event {
19778            SessionEvent::InvalidateInlineValue => {
19779                self.refresh_inline_values(cx);
19780            }
19781            _ => {}
19782        }
19783    }
19784
19785    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19786        let Some(project) = self.project.clone() else {
19787            return;
19788        };
19789
19790        if !self.inline_value_cache.enabled {
19791            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19792            self.splice_inlays(&inlays, Vec::new(), cx);
19793            return;
19794        }
19795
19796        let current_execution_position = self
19797            .highlighted_rows
19798            .get(&TypeId::of::<ActiveDebugLine>())
19799            .and_then(|lines| lines.last().map(|line| line.range.end));
19800
19801        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19802            let inline_values = editor
19803                .update(cx, |editor, cx| {
19804                    let Some(current_execution_position) = current_execution_position else {
19805                        return Some(Task::ready(Ok(Vec::new())));
19806                    };
19807
19808                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19809                        let snapshot = buffer.snapshot(cx);
19810
19811                        let excerpt = snapshot.excerpt_containing(
19812                            current_execution_position..current_execution_position,
19813                        )?;
19814
19815                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19816                    })?;
19817
19818                    let range =
19819                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19820
19821                    project.inline_values(buffer, range, cx)
19822                })
19823                .ok()
19824                .flatten()?
19825                .await
19826                .context("refreshing debugger inlays")
19827                .log_err()?;
19828
19829            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19830
19831            for (buffer_id, inline_value) in inline_values
19832                .into_iter()
19833                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19834            {
19835                buffer_inline_values
19836                    .entry(buffer_id)
19837                    .or_default()
19838                    .push(inline_value);
19839            }
19840
19841            editor
19842                .update(cx, |editor, cx| {
19843                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19844                    let mut new_inlays = Vec::default();
19845
19846                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19847                        let buffer_id = buffer_snapshot.remote_id();
19848                        buffer_inline_values
19849                            .get(&buffer_id)
19850                            .into_iter()
19851                            .flatten()
19852                            .for_each(|hint| {
19853                                let inlay = Inlay::debugger(
19854                                    post_inc(&mut editor.next_inlay_id),
19855                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19856                                    hint.text(),
19857                                );
19858                                if !inlay.text.chars().contains(&'\n') {
19859                                    new_inlays.push(inlay);
19860                                }
19861                            });
19862                    }
19863
19864                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19865                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19866
19867                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19868                })
19869                .ok()?;
19870            Some(())
19871        });
19872    }
19873
19874    fn on_buffer_event(
19875        &mut self,
19876        multibuffer: &Entity<MultiBuffer>,
19877        event: &multi_buffer::Event,
19878        window: &mut Window,
19879        cx: &mut Context<Self>,
19880    ) {
19881        match event {
19882            multi_buffer::Event::Edited {
19883                singleton_buffer_edited,
19884                edited_buffer,
19885            } => {
19886                self.scrollbar_marker_state.dirty = true;
19887                self.active_indent_guides_state.dirty = true;
19888                self.refresh_active_diagnostics(cx);
19889                self.refresh_code_actions(window, cx);
19890                self.refresh_selected_text_highlights(true, window, cx);
19891                self.refresh_single_line_folds(window, cx);
19892                refresh_matching_bracket_highlights(self, window, cx);
19893                if self.has_active_inline_completion() {
19894                    self.update_visible_inline_completion(window, cx);
19895                }
19896                if let Some(project) = self.project.as_ref() {
19897                    if let Some(edited_buffer) = edited_buffer {
19898                        project.update(cx, |project, cx| {
19899                            self.registered_buffers
19900                                .entry(edited_buffer.read(cx).remote_id())
19901                                .or_insert_with(|| {
19902                                    project
19903                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19904                                });
19905                        });
19906                    }
19907                }
19908                cx.emit(EditorEvent::BufferEdited);
19909                cx.emit(SearchEvent::MatchesInvalidated);
19910
19911                if let Some(buffer) = edited_buffer {
19912                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19913                }
19914
19915                if *singleton_buffer_edited {
19916                    if let Some(buffer) = edited_buffer {
19917                        if buffer.read(cx).file().is_none() {
19918                            cx.emit(EditorEvent::TitleChanged);
19919                        }
19920                    }
19921                    if let Some(project) = &self.project {
19922                        #[allow(clippy::mutable_key_type)]
19923                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19924                            multibuffer
19925                                .all_buffers()
19926                                .into_iter()
19927                                .filter_map(|buffer| {
19928                                    buffer.update(cx, |buffer, cx| {
19929                                        let language = buffer.language()?;
19930                                        let should_discard = project.update(cx, |project, cx| {
19931                                            project.is_local()
19932                                                && !project.has_language_servers_for(buffer, cx)
19933                                        });
19934                                        should_discard.not().then_some(language.clone())
19935                                    })
19936                                })
19937                                .collect::<HashSet<_>>()
19938                        });
19939                        if !languages_affected.is_empty() {
19940                            self.refresh_inlay_hints(
19941                                InlayHintRefreshReason::BufferEdited(languages_affected),
19942                                cx,
19943                            );
19944                        }
19945                    }
19946                }
19947
19948                let Some(project) = &self.project else { return };
19949                let (telemetry, is_via_ssh) = {
19950                    let project = project.read(cx);
19951                    let telemetry = project.client().telemetry().clone();
19952                    let is_via_ssh = project.is_via_ssh();
19953                    (telemetry, is_via_ssh)
19954                };
19955                refresh_linked_ranges(self, window, cx);
19956                telemetry.log_edit_event("editor", is_via_ssh);
19957            }
19958            multi_buffer::Event::ExcerptsAdded {
19959                buffer,
19960                predecessor,
19961                excerpts,
19962            } => {
19963                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19964                let buffer_id = buffer.read(cx).remote_id();
19965                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19966                    if let Some(project) = &self.project {
19967                        update_uncommitted_diff_for_buffer(
19968                            cx.entity(),
19969                            project,
19970                            [buffer.clone()],
19971                            self.buffer.clone(),
19972                            cx,
19973                        )
19974                        .detach();
19975                    }
19976                }
19977                self.update_lsp_data(false, Some(buffer_id), window, cx);
19978                cx.emit(EditorEvent::ExcerptsAdded {
19979                    buffer: buffer.clone(),
19980                    predecessor: *predecessor,
19981                    excerpts: excerpts.clone(),
19982                });
19983                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19984            }
19985            multi_buffer::Event::ExcerptsRemoved {
19986                ids,
19987                removed_buffer_ids,
19988            } => {
19989                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19990                let buffer = self.buffer.read(cx);
19991                self.registered_buffers
19992                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19993                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19994                cx.emit(EditorEvent::ExcerptsRemoved {
19995                    ids: ids.clone(),
19996                    removed_buffer_ids: removed_buffer_ids.clone(),
19997                });
19998            }
19999            multi_buffer::Event::ExcerptsEdited {
20000                excerpt_ids,
20001                buffer_ids,
20002            } => {
20003                self.display_map.update(cx, |map, cx| {
20004                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20005                });
20006                cx.emit(EditorEvent::ExcerptsEdited {
20007                    ids: excerpt_ids.clone(),
20008                });
20009            }
20010            multi_buffer::Event::ExcerptsExpanded { ids } => {
20011                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20012                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20013            }
20014            multi_buffer::Event::Reparsed(buffer_id) => {
20015                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20016                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20017
20018                cx.emit(EditorEvent::Reparsed(*buffer_id));
20019            }
20020            multi_buffer::Event::DiffHunksToggled => {
20021                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20022            }
20023            multi_buffer::Event::LanguageChanged(buffer_id) => {
20024                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20025                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20026                cx.emit(EditorEvent::Reparsed(*buffer_id));
20027                cx.notify();
20028            }
20029            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20030            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20031            multi_buffer::Event::FileHandleChanged
20032            | multi_buffer::Event::Reloaded
20033            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20034            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20035            multi_buffer::Event::DiagnosticsUpdated => {
20036                self.update_diagnostics_state(window, cx);
20037            }
20038            _ => {}
20039        };
20040    }
20041
20042    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20043        if !self.diagnostics_enabled() {
20044            return;
20045        }
20046        self.refresh_active_diagnostics(cx);
20047        self.refresh_inline_diagnostics(true, window, cx);
20048        self.scrollbar_marker_state.dirty = true;
20049        cx.notify();
20050    }
20051
20052    pub fn start_temporary_diff_override(&mut self) {
20053        self.load_diff_task.take();
20054        self.temporary_diff_override = true;
20055    }
20056
20057    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20058        self.temporary_diff_override = false;
20059        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20060        self.buffer.update(cx, |buffer, cx| {
20061            buffer.set_all_diff_hunks_collapsed(cx);
20062        });
20063
20064        if let Some(project) = self.project.clone() {
20065            self.load_diff_task = Some(
20066                update_uncommitted_diff_for_buffer(
20067                    cx.entity(),
20068                    &project,
20069                    self.buffer.read(cx).all_buffers(),
20070                    self.buffer.clone(),
20071                    cx,
20072                )
20073                .shared(),
20074            );
20075        }
20076    }
20077
20078    fn on_display_map_changed(
20079        &mut self,
20080        _: Entity<DisplayMap>,
20081        _: &mut Window,
20082        cx: &mut Context<Self>,
20083    ) {
20084        cx.notify();
20085    }
20086
20087    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20088        if self.diagnostics_enabled() {
20089            let new_severity = EditorSettings::get_global(cx)
20090                .diagnostics_max_severity
20091                .unwrap_or(DiagnosticSeverity::Hint);
20092            self.set_max_diagnostics_severity(new_severity, cx);
20093        }
20094        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20095        self.update_edit_prediction_settings(cx);
20096        self.refresh_inline_completion(true, false, window, cx);
20097        self.refresh_inline_values(cx);
20098        self.refresh_inlay_hints(
20099            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20100                self.selections.newest_anchor().head(),
20101                &self.buffer.read(cx).snapshot(cx),
20102                cx,
20103            )),
20104            cx,
20105        );
20106
20107        let old_cursor_shape = self.cursor_shape;
20108
20109        {
20110            let editor_settings = EditorSettings::get_global(cx);
20111            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20112            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20113            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20114            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20115        }
20116
20117        if old_cursor_shape != self.cursor_shape {
20118            cx.emit(EditorEvent::CursorShapeChanged);
20119        }
20120
20121        let project_settings = ProjectSettings::get_global(cx);
20122        self.serialize_dirty_buffers =
20123            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20124
20125        if self.mode.is_full() {
20126            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20127            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20128            if self.show_inline_diagnostics != show_inline_diagnostics {
20129                self.show_inline_diagnostics = show_inline_diagnostics;
20130                self.refresh_inline_diagnostics(false, window, cx);
20131            }
20132
20133            if self.git_blame_inline_enabled != inline_blame_enabled {
20134                self.toggle_git_blame_inline_internal(false, window, cx);
20135            }
20136
20137            let minimap_settings = EditorSettings::get_global(cx).minimap;
20138            if self.minimap_visibility != MinimapVisibility::Disabled {
20139                if self.minimap_visibility.settings_visibility()
20140                    != minimap_settings.minimap_enabled()
20141                {
20142                    self.set_minimap_visibility(
20143                        MinimapVisibility::for_mode(self.mode(), cx),
20144                        window,
20145                        cx,
20146                    );
20147                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20148                    minimap_entity.update(cx, |minimap_editor, cx| {
20149                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20150                    })
20151                }
20152            }
20153        }
20154
20155        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20156            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20157        }) {
20158            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20159                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20160            }
20161            self.refresh_colors(false, None, window, cx);
20162        }
20163
20164        cx.notify();
20165    }
20166
20167    pub fn set_searchable(&mut self, searchable: bool) {
20168        self.searchable = searchable;
20169    }
20170
20171    pub fn searchable(&self) -> bool {
20172        self.searchable
20173    }
20174
20175    fn open_proposed_changes_editor(
20176        &mut self,
20177        _: &OpenProposedChangesEditor,
20178        window: &mut Window,
20179        cx: &mut Context<Self>,
20180    ) {
20181        let Some(workspace) = self.workspace() else {
20182            cx.propagate();
20183            return;
20184        };
20185
20186        let selections = self.selections.all::<usize>(cx);
20187        let multi_buffer = self.buffer.read(cx);
20188        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20189        let mut new_selections_by_buffer = HashMap::default();
20190        for selection in selections {
20191            for (buffer, range, _) in
20192                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20193            {
20194                let mut range = range.to_point(buffer);
20195                range.start.column = 0;
20196                range.end.column = buffer.line_len(range.end.row);
20197                new_selections_by_buffer
20198                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20199                    .or_insert(Vec::new())
20200                    .push(range)
20201            }
20202        }
20203
20204        let proposed_changes_buffers = new_selections_by_buffer
20205            .into_iter()
20206            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20207            .collect::<Vec<_>>();
20208        let proposed_changes_editor = cx.new(|cx| {
20209            ProposedChangesEditor::new(
20210                "Proposed changes",
20211                proposed_changes_buffers,
20212                self.project.clone(),
20213                window,
20214                cx,
20215            )
20216        });
20217
20218        window.defer(cx, move |window, cx| {
20219            workspace.update(cx, |workspace, cx| {
20220                workspace.active_pane().update(cx, |pane, cx| {
20221                    pane.add_item(
20222                        Box::new(proposed_changes_editor),
20223                        true,
20224                        true,
20225                        None,
20226                        window,
20227                        cx,
20228                    );
20229                });
20230            });
20231        });
20232    }
20233
20234    pub fn open_excerpts_in_split(
20235        &mut self,
20236        _: &OpenExcerptsSplit,
20237        window: &mut Window,
20238        cx: &mut Context<Self>,
20239    ) {
20240        self.open_excerpts_common(None, true, window, cx)
20241    }
20242
20243    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20244        self.open_excerpts_common(None, false, window, cx)
20245    }
20246
20247    fn open_excerpts_common(
20248        &mut self,
20249        jump_data: Option<JumpData>,
20250        split: bool,
20251        window: &mut Window,
20252        cx: &mut Context<Self>,
20253    ) {
20254        let Some(workspace) = self.workspace() else {
20255            cx.propagate();
20256            return;
20257        };
20258
20259        if self.buffer.read(cx).is_singleton() {
20260            cx.propagate();
20261            return;
20262        }
20263
20264        let mut new_selections_by_buffer = HashMap::default();
20265        match &jump_data {
20266            Some(JumpData::MultiBufferPoint {
20267                excerpt_id,
20268                position,
20269                anchor,
20270                line_offset_from_top,
20271            }) => {
20272                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20273                if let Some(buffer) = multi_buffer_snapshot
20274                    .buffer_id_for_excerpt(*excerpt_id)
20275                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20276                {
20277                    let buffer_snapshot = buffer.read(cx).snapshot();
20278                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20279                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20280                    } else {
20281                        buffer_snapshot.clip_point(*position, Bias::Left)
20282                    };
20283                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20284                    new_selections_by_buffer.insert(
20285                        buffer,
20286                        (
20287                            vec![jump_to_offset..jump_to_offset],
20288                            Some(*line_offset_from_top),
20289                        ),
20290                    );
20291                }
20292            }
20293            Some(JumpData::MultiBufferRow {
20294                row,
20295                line_offset_from_top,
20296            }) => {
20297                let point = MultiBufferPoint::new(row.0, 0);
20298                if let Some((buffer, buffer_point, _)) =
20299                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20300                {
20301                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20302                    new_selections_by_buffer
20303                        .entry(buffer)
20304                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20305                        .0
20306                        .push(buffer_offset..buffer_offset)
20307                }
20308            }
20309            None => {
20310                let selections = self.selections.all::<usize>(cx);
20311                let multi_buffer = self.buffer.read(cx);
20312                for selection in selections {
20313                    for (snapshot, range, _, anchor) in multi_buffer
20314                        .snapshot(cx)
20315                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20316                    {
20317                        if let Some(anchor) = anchor {
20318                            // selection is in a deleted hunk
20319                            let Some(buffer_id) = anchor.buffer_id else {
20320                                continue;
20321                            };
20322                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20323                                continue;
20324                            };
20325                            let offset = text::ToOffset::to_offset(
20326                                &anchor.text_anchor,
20327                                &buffer_handle.read(cx).snapshot(),
20328                            );
20329                            let range = offset..offset;
20330                            new_selections_by_buffer
20331                                .entry(buffer_handle)
20332                                .or_insert((Vec::new(), None))
20333                                .0
20334                                .push(range)
20335                        } else {
20336                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20337                            else {
20338                                continue;
20339                            };
20340                            new_selections_by_buffer
20341                                .entry(buffer_handle)
20342                                .or_insert((Vec::new(), None))
20343                                .0
20344                                .push(range)
20345                        }
20346                    }
20347                }
20348            }
20349        }
20350
20351        new_selections_by_buffer
20352            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20353
20354        if new_selections_by_buffer.is_empty() {
20355            return;
20356        }
20357
20358        // We defer the pane interaction because we ourselves are a workspace item
20359        // and activating a new item causes the pane to call a method on us reentrantly,
20360        // which panics if we're on the stack.
20361        window.defer(cx, move |window, cx| {
20362            workspace.update(cx, |workspace, cx| {
20363                let pane = if split {
20364                    workspace.adjacent_pane(window, cx)
20365                } else {
20366                    workspace.active_pane().clone()
20367                };
20368
20369                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20370                    let editor = buffer
20371                        .read(cx)
20372                        .file()
20373                        .is_none()
20374                        .then(|| {
20375                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20376                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20377                            // Instead, we try to activate the existing editor in the pane first.
20378                            let (editor, pane_item_index) =
20379                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20380                                    let editor = item.downcast::<Editor>()?;
20381                                    let singleton_buffer =
20382                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20383                                    if singleton_buffer == buffer {
20384                                        Some((editor, i))
20385                                    } else {
20386                                        None
20387                                    }
20388                                })?;
20389                            pane.update(cx, |pane, cx| {
20390                                pane.activate_item(pane_item_index, true, true, window, cx)
20391                            });
20392                            Some(editor)
20393                        })
20394                        .flatten()
20395                        .unwrap_or_else(|| {
20396                            workspace.open_project_item::<Self>(
20397                                pane.clone(),
20398                                buffer,
20399                                true,
20400                                true,
20401                                window,
20402                                cx,
20403                            )
20404                        });
20405
20406                    editor.update(cx, |editor, cx| {
20407                        let autoscroll = match scroll_offset {
20408                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20409                            None => Autoscroll::newest(),
20410                        };
20411                        let nav_history = editor.nav_history.take();
20412                        editor.change_selections(
20413                            SelectionEffects::scroll(autoscroll),
20414                            window,
20415                            cx,
20416                            |s| {
20417                                s.select_ranges(ranges);
20418                            },
20419                        );
20420                        editor.nav_history = nav_history;
20421                    });
20422                }
20423            })
20424        });
20425    }
20426
20427    // For now, don't allow opening excerpts in buffers that aren't backed by
20428    // regular project files.
20429    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20430        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20431    }
20432
20433    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20434        let snapshot = self.buffer.read(cx).read(cx);
20435        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20436        Some(
20437            ranges
20438                .iter()
20439                .map(move |range| {
20440                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20441                })
20442                .collect(),
20443        )
20444    }
20445
20446    fn selection_replacement_ranges(
20447        &self,
20448        range: Range<OffsetUtf16>,
20449        cx: &mut App,
20450    ) -> Vec<Range<OffsetUtf16>> {
20451        let selections = self.selections.all::<OffsetUtf16>(cx);
20452        let newest_selection = selections
20453            .iter()
20454            .max_by_key(|selection| selection.id)
20455            .unwrap();
20456        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20457        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20458        let snapshot = self.buffer.read(cx).read(cx);
20459        selections
20460            .into_iter()
20461            .map(|mut selection| {
20462                selection.start.0 =
20463                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20464                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20465                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20466                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20467            })
20468            .collect()
20469    }
20470
20471    fn report_editor_event(
20472        &self,
20473        event_type: &'static str,
20474        file_extension: Option<String>,
20475        cx: &App,
20476    ) {
20477        if cfg!(any(test, feature = "test-support")) {
20478            return;
20479        }
20480
20481        let Some(project) = &self.project else { return };
20482
20483        // If None, we are in a file without an extension
20484        let file = self
20485            .buffer
20486            .read(cx)
20487            .as_singleton()
20488            .and_then(|b| b.read(cx).file());
20489        let file_extension = file_extension.or(file
20490            .as_ref()
20491            .and_then(|file| Path::new(file.file_name(cx)).extension())
20492            .and_then(|e| e.to_str())
20493            .map(|a| a.to_string()));
20494
20495        let vim_mode = vim_enabled(cx);
20496
20497        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20498        let copilot_enabled = edit_predictions_provider
20499            == language::language_settings::EditPredictionProvider::Copilot;
20500        let copilot_enabled_for_language = self
20501            .buffer
20502            .read(cx)
20503            .language_settings(cx)
20504            .show_edit_predictions;
20505
20506        let project = project.read(cx);
20507        telemetry::event!(
20508            event_type,
20509            file_extension,
20510            vim_mode,
20511            copilot_enabled,
20512            copilot_enabled_for_language,
20513            edit_predictions_provider,
20514            is_via_ssh = project.is_via_ssh(),
20515        );
20516    }
20517
20518    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20519    /// with each line being an array of {text, highlight} objects.
20520    fn copy_highlight_json(
20521        &mut self,
20522        _: &CopyHighlightJson,
20523        window: &mut Window,
20524        cx: &mut Context<Self>,
20525    ) {
20526        #[derive(Serialize)]
20527        struct Chunk<'a> {
20528            text: String,
20529            highlight: Option<&'a str>,
20530        }
20531
20532        let snapshot = self.buffer.read(cx).snapshot(cx);
20533        let range = self
20534            .selected_text_range(false, window, cx)
20535            .and_then(|selection| {
20536                if selection.range.is_empty() {
20537                    None
20538                } else {
20539                    Some(selection.range)
20540                }
20541            })
20542            .unwrap_or_else(|| 0..snapshot.len());
20543
20544        let chunks = snapshot.chunks(range, true);
20545        let mut lines = Vec::new();
20546        let mut line: VecDeque<Chunk> = VecDeque::new();
20547
20548        let Some(style) = self.style.as_ref() else {
20549            return;
20550        };
20551
20552        for chunk in chunks {
20553            let highlight = chunk
20554                .syntax_highlight_id
20555                .and_then(|id| id.name(&style.syntax));
20556            let mut chunk_lines = chunk.text.split('\n').peekable();
20557            while let Some(text) = chunk_lines.next() {
20558                let mut merged_with_last_token = false;
20559                if let Some(last_token) = line.back_mut() {
20560                    if last_token.highlight == highlight {
20561                        last_token.text.push_str(text);
20562                        merged_with_last_token = true;
20563                    }
20564                }
20565
20566                if !merged_with_last_token {
20567                    line.push_back(Chunk {
20568                        text: text.into(),
20569                        highlight,
20570                    });
20571                }
20572
20573                if chunk_lines.peek().is_some() {
20574                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20575                        line.pop_front();
20576                    }
20577                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20578                        line.pop_back();
20579                    }
20580
20581                    lines.push(mem::take(&mut line));
20582                }
20583            }
20584        }
20585
20586        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20587            return;
20588        };
20589        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20590    }
20591
20592    pub fn open_context_menu(
20593        &mut self,
20594        _: &OpenContextMenu,
20595        window: &mut Window,
20596        cx: &mut Context<Self>,
20597    ) {
20598        self.request_autoscroll(Autoscroll::newest(), cx);
20599        let position = self.selections.newest_display(cx).start;
20600        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20601    }
20602
20603    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20604        &self.inlay_hint_cache
20605    }
20606
20607    pub fn replay_insert_event(
20608        &mut self,
20609        text: &str,
20610        relative_utf16_range: Option<Range<isize>>,
20611        window: &mut Window,
20612        cx: &mut Context<Self>,
20613    ) {
20614        if !self.input_enabled {
20615            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20616            return;
20617        }
20618        if let Some(relative_utf16_range) = relative_utf16_range {
20619            let selections = self.selections.all::<OffsetUtf16>(cx);
20620            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20621                let new_ranges = selections.into_iter().map(|range| {
20622                    let start = OffsetUtf16(
20623                        range
20624                            .head()
20625                            .0
20626                            .saturating_add_signed(relative_utf16_range.start),
20627                    );
20628                    let end = OffsetUtf16(
20629                        range
20630                            .head()
20631                            .0
20632                            .saturating_add_signed(relative_utf16_range.end),
20633                    );
20634                    start..end
20635                });
20636                s.select_ranges(new_ranges);
20637            });
20638        }
20639
20640        self.handle_input(text, window, cx);
20641    }
20642
20643    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20644        let Some(provider) = self.semantics_provider.as_ref() else {
20645            return false;
20646        };
20647
20648        let mut supports = false;
20649        self.buffer().update(cx, |this, cx| {
20650            this.for_each_buffer(|buffer| {
20651                supports |= provider.supports_inlay_hints(buffer, cx);
20652            });
20653        });
20654
20655        supports
20656    }
20657
20658    pub fn is_focused(&self, window: &Window) -> bool {
20659        self.focus_handle.is_focused(window)
20660    }
20661
20662    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20663        cx.emit(EditorEvent::Focused);
20664
20665        if let Some(descendant) = self
20666            .last_focused_descendant
20667            .take()
20668            .and_then(|descendant| descendant.upgrade())
20669        {
20670            window.focus(&descendant);
20671        } else {
20672            if let Some(blame) = self.blame.as_ref() {
20673                blame.update(cx, GitBlame::focus)
20674            }
20675
20676            self.blink_manager.update(cx, BlinkManager::enable);
20677            self.show_cursor_names(window, cx);
20678            self.buffer.update(cx, |buffer, cx| {
20679                buffer.finalize_last_transaction(cx);
20680                if self.leader_id.is_none() {
20681                    buffer.set_active_selections(
20682                        &self.selections.disjoint_anchors(),
20683                        self.selections.line_mode,
20684                        self.cursor_shape,
20685                        cx,
20686                    );
20687                }
20688            });
20689        }
20690    }
20691
20692    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20693        cx.emit(EditorEvent::FocusedIn)
20694    }
20695
20696    fn handle_focus_out(
20697        &mut self,
20698        event: FocusOutEvent,
20699        _window: &mut Window,
20700        cx: &mut Context<Self>,
20701    ) {
20702        if event.blurred != self.focus_handle {
20703            self.last_focused_descendant = Some(event.blurred);
20704        }
20705        self.selection_drag_state = SelectionDragState::None;
20706        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20707    }
20708
20709    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20710        self.blink_manager.update(cx, BlinkManager::disable);
20711        self.buffer
20712            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20713
20714        if let Some(blame) = self.blame.as_ref() {
20715            blame.update(cx, GitBlame::blur)
20716        }
20717        if !self.hover_state.focused(window, cx) {
20718            hide_hover(self, cx);
20719        }
20720        if !self
20721            .context_menu
20722            .borrow()
20723            .as_ref()
20724            .is_some_and(|context_menu| context_menu.focused(window, cx))
20725        {
20726            self.hide_context_menu(window, cx);
20727        }
20728        self.discard_inline_completion(false, cx);
20729        cx.emit(EditorEvent::Blurred);
20730        cx.notify();
20731    }
20732
20733    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20734        let mut pending: String = window
20735            .pending_input_keystrokes()
20736            .into_iter()
20737            .flatten()
20738            .filter_map(|keystroke| {
20739                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20740                    keystroke.key_char.clone()
20741                } else {
20742                    None
20743                }
20744            })
20745            .collect();
20746
20747        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20748            pending = "".to_string();
20749        }
20750
20751        let existing_pending = self
20752            .text_highlights::<PendingInput>(cx)
20753            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20754        if existing_pending.is_none() && pending.is_empty() {
20755            return;
20756        }
20757        let transaction =
20758            self.transact(window, cx, |this, window, cx| {
20759                let selections = this.selections.all::<usize>(cx);
20760                let edits = selections
20761                    .iter()
20762                    .map(|selection| (selection.end..selection.end, pending.clone()));
20763                this.edit(edits, cx);
20764                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20765                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20766                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20767                    }));
20768                });
20769                if let Some(existing_ranges) = existing_pending {
20770                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20771                    this.edit(edits, cx);
20772                }
20773            });
20774
20775        let snapshot = self.snapshot(window, cx);
20776        let ranges = self
20777            .selections
20778            .all::<usize>(cx)
20779            .into_iter()
20780            .map(|selection| {
20781                snapshot.buffer_snapshot.anchor_after(selection.end)
20782                    ..snapshot
20783                        .buffer_snapshot
20784                        .anchor_before(selection.end + pending.len())
20785            })
20786            .collect();
20787
20788        if pending.is_empty() {
20789            self.clear_highlights::<PendingInput>(cx);
20790        } else {
20791            self.highlight_text::<PendingInput>(
20792                ranges,
20793                HighlightStyle {
20794                    underline: Some(UnderlineStyle {
20795                        thickness: px(1.),
20796                        color: None,
20797                        wavy: false,
20798                    }),
20799                    ..Default::default()
20800                },
20801                cx,
20802            );
20803        }
20804
20805        self.ime_transaction = self.ime_transaction.or(transaction);
20806        if let Some(transaction) = self.ime_transaction {
20807            self.buffer.update(cx, |buffer, cx| {
20808                buffer.group_until_transaction(transaction, cx);
20809            });
20810        }
20811
20812        if self.text_highlights::<PendingInput>(cx).is_none() {
20813            self.ime_transaction.take();
20814        }
20815    }
20816
20817    pub fn register_action_renderer(
20818        &mut self,
20819        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20820    ) -> Subscription {
20821        let id = self.next_editor_action_id.post_inc();
20822        self.editor_actions
20823            .borrow_mut()
20824            .insert(id, Box::new(listener));
20825
20826        let editor_actions = self.editor_actions.clone();
20827        Subscription::new(move || {
20828            editor_actions.borrow_mut().remove(&id);
20829        })
20830    }
20831
20832    pub fn register_action<A: Action>(
20833        &mut self,
20834        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20835    ) -> Subscription {
20836        let id = self.next_editor_action_id.post_inc();
20837        let listener = Arc::new(listener);
20838        self.editor_actions.borrow_mut().insert(
20839            id,
20840            Box::new(move |_, window, _| {
20841                let listener = listener.clone();
20842                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20843                    let action = action.downcast_ref().unwrap();
20844                    if phase == DispatchPhase::Bubble {
20845                        listener(action, window, cx)
20846                    }
20847                })
20848            }),
20849        );
20850
20851        let editor_actions = self.editor_actions.clone();
20852        Subscription::new(move || {
20853            editor_actions.borrow_mut().remove(&id);
20854        })
20855    }
20856
20857    pub fn file_header_size(&self) -> u32 {
20858        FILE_HEADER_HEIGHT
20859    }
20860
20861    pub fn restore(
20862        &mut self,
20863        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20864        window: &mut Window,
20865        cx: &mut Context<Self>,
20866    ) {
20867        let workspace = self.workspace();
20868        let project = self.project.as_ref();
20869        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20870            let mut tasks = Vec::new();
20871            for (buffer_id, changes) in revert_changes {
20872                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20873                    buffer.update(cx, |buffer, cx| {
20874                        buffer.edit(
20875                            changes
20876                                .into_iter()
20877                                .map(|(range, text)| (range, text.to_string())),
20878                            None,
20879                            cx,
20880                        );
20881                    });
20882
20883                    if let Some(project) =
20884                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20885                    {
20886                        project.update(cx, |project, cx| {
20887                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20888                        })
20889                    }
20890                }
20891            }
20892            tasks
20893        });
20894        cx.spawn_in(window, async move |_, cx| {
20895            for (buffer, task) in save_tasks {
20896                let result = task.await;
20897                if result.is_err() {
20898                    let Some(path) = buffer
20899                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20900                        .ok()
20901                    else {
20902                        continue;
20903                    };
20904                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20905                        let Some(task) = cx
20906                            .update_window_entity(&workspace, |workspace, window, cx| {
20907                                workspace
20908                                    .open_path_preview(path, None, false, false, false, window, cx)
20909                            })
20910                            .ok()
20911                        else {
20912                            continue;
20913                        };
20914                        task.await.log_err();
20915                    }
20916                }
20917            }
20918        })
20919        .detach();
20920        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20921            selections.refresh()
20922        });
20923    }
20924
20925    pub fn to_pixel_point(
20926        &self,
20927        source: multi_buffer::Anchor,
20928        editor_snapshot: &EditorSnapshot,
20929        window: &mut Window,
20930    ) -> Option<gpui::Point<Pixels>> {
20931        let source_point = source.to_display_point(editor_snapshot);
20932        self.display_to_pixel_point(source_point, editor_snapshot, window)
20933    }
20934
20935    pub fn display_to_pixel_point(
20936        &self,
20937        source: DisplayPoint,
20938        editor_snapshot: &EditorSnapshot,
20939        window: &mut Window,
20940    ) -> Option<gpui::Point<Pixels>> {
20941        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20942        let text_layout_details = self.text_layout_details(window);
20943        let scroll_top = text_layout_details
20944            .scroll_anchor
20945            .scroll_position(editor_snapshot)
20946            .y;
20947
20948        if source.row().as_f32() < scroll_top.floor() {
20949            return None;
20950        }
20951        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20952        let source_y = line_height * (source.row().as_f32() - scroll_top);
20953        Some(gpui::Point::new(source_x, source_y))
20954    }
20955
20956    pub fn has_visible_completions_menu(&self) -> bool {
20957        !self.edit_prediction_preview_is_active()
20958            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20959                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20960            })
20961    }
20962
20963    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20964        if self.mode.is_minimap() {
20965            return;
20966        }
20967        self.addons
20968            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20969    }
20970
20971    pub fn unregister_addon<T: Addon>(&mut self) {
20972        self.addons.remove(&std::any::TypeId::of::<T>());
20973    }
20974
20975    pub fn addon<T: Addon>(&self) -> Option<&T> {
20976        let type_id = std::any::TypeId::of::<T>();
20977        self.addons
20978            .get(&type_id)
20979            .and_then(|item| item.to_any().downcast_ref::<T>())
20980    }
20981
20982    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20983        let type_id = std::any::TypeId::of::<T>();
20984        self.addons
20985            .get_mut(&type_id)
20986            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20987    }
20988
20989    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20990        let text_layout_details = self.text_layout_details(window);
20991        let style = &text_layout_details.editor_style;
20992        let font_id = window.text_system().resolve_font(&style.text.font());
20993        let font_size = style.text.font_size.to_pixels(window.rem_size());
20994        let line_height = style.text.line_height_in_pixels(window.rem_size());
20995        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20996        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20997
20998        CharacterDimensions {
20999            em_width,
21000            em_advance,
21001            line_height,
21002        }
21003    }
21004
21005    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21006        self.load_diff_task.clone()
21007    }
21008
21009    fn read_metadata_from_db(
21010        &mut self,
21011        item_id: u64,
21012        workspace_id: WorkspaceId,
21013        window: &mut Window,
21014        cx: &mut Context<Editor>,
21015    ) {
21016        if self.is_singleton(cx)
21017            && !self.mode.is_minimap()
21018            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21019        {
21020            let buffer_snapshot = OnceCell::new();
21021
21022            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21023                if !folds.is_empty() {
21024                    let snapshot =
21025                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21026                    self.fold_ranges(
21027                        folds
21028                            .into_iter()
21029                            .map(|(start, end)| {
21030                                snapshot.clip_offset(start, Bias::Left)
21031                                    ..snapshot.clip_offset(end, Bias::Right)
21032                            })
21033                            .collect(),
21034                        false,
21035                        window,
21036                        cx,
21037                    );
21038                }
21039            }
21040
21041            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21042                if !selections.is_empty() {
21043                    let snapshot =
21044                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21045                    // skip adding the initial selection to selection history
21046                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21047                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21048                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21049                            snapshot.clip_offset(start, Bias::Left)
21050                                ..snapshot.clip_offset(end, Bias::Right)
21051                        }));
21052                    });
21053                    self.selection_history.mode = SelectionHistoryMode::Normal;
21054                }
21055            };
21056        }
21057
21058        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21059    }
21060
21061    fn update_lsp_data(
21062        &mut self,
21063        ignore_cache: bool,
21064        for_buffer: Option<BufferId>,
21065        window: &mut Window,
21066        cx: &mut Context<'_, Self>,
21067    ) {
21068        self.pull_diagnostics(for_buffer, window, cx);
21069        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21070    }
21071}
21072
21073fn vim_enabled(cx: &App) -> bool {
21074    cx.global::<SettingsStore>()
21075        .raw_user_settings()
21076        .get("vim_mode")
21077        == Some(&serde_json::Value::Bool(true))
21078}
21079
21080fn process_completion_for_edit(
21081    completion: &Completion,
21082    intent: CompletionIntent,
21083    buffer: &Entity<Buffer>,
21084    cursor_position: &text::Anchor,
21085    cx: &mut Context<Editor>,
21086) -> CompletionEdit {
21087    let buffer = buffer.read(cx);
21088    let buffer_snapshot = buffer.snapshot();
21089    let (snippet, new_text) = if completion.is_snippet() {
21090        // Workaround for typescript language server issues so that methods don't expand within
21091        // strings and functions with type expressions. The previous point is used because the query
21092        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21093        let mut snippet_source = completion.new_text.clone();
21094        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21095        previous_point.column = previous_point.column.saturating_sub(1);
21096        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21097            if scope.prefers_label_for_snippet_in_completion() {
21098                if let Some(label) = completion.label() {
21099                    if matches!(
21100                        completion.kind(),
21101                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21102                    ) {
21103                        snippet_source = label;
21104                    }
21105                }
21106            }
21107        }
21108        match Snippet::parse(&snippet_source).log_err() {
21109            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21110            None => (None, completion.new_text.clone()),
21111        }
21112    } else {
21113        (None, completion.new_text.clone())
21114    };
21115
21116    let mut range_to_replace = {
21117        let replace_range = &completion.replace_range;
21118        if let CompletionSource::Lsp {
21119            insert_range: Some(insert_range),
21120            ..
21121        } = &completion.source
21122        {
21123            debug_assert_eq!(
21124                insert_range.start, replace_range.start,
21125                "insert_range and replace_range should start at the same position"
21126            );
21127            debug_assert!(
21128                insert_range
21129                    .start
21130                    .cmp(&cursor_position, &buffer_snapshot)
21131                    .is_le(),
21132                "insert_range should start before or at cursor position"
21133            );
21134            debug_assert!(
21135                replace_range
21136                    .start
21137                    .cmp(&cursor_position, &buffer_snapshot)
21138                    .is_le(),
21139                "replace_range should start before or at cursor position"
21140            );
21141            debug_assert!(
21142                insert_range
21143                    .end
21144                    .cmp(&cursor_position, &buffer_snapshot)
21145                    .is_le(),
21146                "insert_range should end before or at cursor position"
21147            );
21148
21149            let should_replace = match intent {
21150                CompletionIntent::CompleteWithInsert => false,
21151                CompletionIntent::CompleteWithReplace => true,
21152                CompletionIntent::Complete | CompletionIntent::Compose => {
21153                    let insert_mode =
21154                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21155                            .completions
21156                            .lsp_insert_mode;
21157                    match insert_mode {
21158                        LspInsertMode::Insert => false,
21159                        LspInsertMode::Replace => true,
21160                        LspInsertMode::ReplaceSubsequence => {
21161                            let mut text_to_replace = buffer.chars_for_range(
21162                                buffer.anchor_before(replace_range.start)
21163                                    ..buffer.anchor_after(replace_range.end),
21164                            );
21165                            let mut current_needle = text_to_replace.next();
21166                            for haystack_ch in completion.label.text.chars() {
21167                                if let Some(needle_ch) = current_needle {
21168                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21169                                        current_needle = text_to_replace.next();
21170                                    }
21171                                }
21172                            }
21173                            current_needle.is_none()
21174                        }
21175                        LspInsertMode::ReplaceSuffix => {
21176                            if replace_range
21177                                .end
21178                                .cmp(&cursor_position, &buffer_snapshot)
21179                                .is_gt()
21180                            {
21181                                let range_after_cursor = *cursor_position..replace_range.end;
21182                                let text_after_cursor = buffer
21183                                    .text_for_range(
21184                                        buffer.anchor_before(range_after_cursor.start)
21185                                            ..buffer.anchor_after(range_after_cursor.end),
21186                                    )
21187                                    .collect::<String>()
21188                                    .to_ascii_lowercase();
21189                                completion
21190                                    .label
21191                                    .text
21192                                    .to_ascii_lowercase()
21193                                    .ends_with(&text_after_cursor)
21194                            } else {
21195                                true
21196                            }
21197                        }
21198                    }
21199                }
21200            };
21201
21202            if should_replace {
21203                replace_range.clone()
21204            } else {
21205                insert_range.clone()
21206            }
21207        } else {
21208            replace_range.clone()
21209        }
21210    };
21211
21212    if range_to_replace
21213        .end
21214        .cmp(&cursor_position, &buffer_snapshot)
21215        .is_lt()
21216    {
21217        range_to_replace.end = *cursor_position;
21218    }
21219
21220    CompletionEdit {
21221        new_text,
21222        replace_range: range_to_replace.to_offset(&buffer),
21223        snippet,
21224    }
21225}
21226
21227struct CompletionEdit {
21228    new_text: String,
21229    replace_range: Range<usize>,
21230    snippet: Option<Snippet>,
21231}
21232
21233fn insert_extra_newline_brackets(
21234    buffer: &MultiBufferSnapshot,
21235    range: Range<usize>,
21236    language: &language::LanguageScope,
21237) -> bool {
21238    let leading_whitespace_len = buffer
21239        .reversed_chars_at(range.start)
21240        .take_while(|c| c.is_whitespace() && *c != '\n')
21241        .map(|c| c.len_utf8())
21242        .sum::<usize>();
21243    let trailing_whitespace_len = buffer
21244        .chars_at(range.end)
21245        .take_while(|c| c.is_whitespace() && *c != '\n')
21246        .map(|c| c.len_utf8())
21247        .sum::<usize>();
21248    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21249
21250    language.brackets().any(|(pair, enabled)| {
21251        let pair_start = pair.start.trim_end();
21252        let pair_end = pair.end.trim_start();
21253
21254        enabled
21255            && pair.newline
21256            && buffer.contains_str_at(range.end, pair_end)
21257            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21258    })
21259}
21260
21261fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21262    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21263        [(buffer, range, _)] => (*buffer, range.clone()),
21264        _ => return false,
21265    };
21266    let pair = {
21267        let mut result: Option<BracketMatch> = None;
21268
21269        for pair in buffer
21270            .all_bracket_ranges(range.clone())
21271            .filter(move |pair| {
21272                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21273            })
21274        {
21275            let len = pair.close_range.end - pair.open_range.start;
21276
21277            if let Some(existing) = &result {
21278                let existing_len = existing.close_range.end - existing.open_range.start;
21279                if len > existing_len {
21280                    continue;
21281                }
21282            }
21283
21284            result = Some(pair);
21285        }
21286
21287        result
21288    };
21289    let Some(pair) = pair else {
21290        return false;
21291    };
21292    pair.newline_only
21293        && buffer
21294            .chars_for_range(pair.open_range.end..range.start)
21295            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21296            .all(|c| c.is_whitespace() && c != '\n')
21297}
21298
21299fn update_uncommitted_diff_for_buffer(
21300    editor: Entity<Editor>,
21301    project: &Entity<Project>,
21302    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21303    buffer: Entity<MultiBuffer>,
21304    cx: &mut App,
21305) -> Task<()> {
21306    let mut tasks = Vec::new();
21307    project.update(cx, |project, cx| {
21308        for buffer in buffers {
21309            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21310                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21311            }
21312        }
21313    });
21314    cx.spawn(async move |cx| {
21315        let diffs = future::join_all(tasks).await;
21316        if editor
21317            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21318            .unwrap_or(false)
21319        {
21320            return;
21321        }
21322
21323        buffer
21324            .update(cx, |buffer, cx| {
21325                for diff in diffs.into_iter().flatten() {
21326                    buffer.add_diff(diff, cx);
21327                }
21328            })
21329            .ok();
21330    })
21331}
21332
21333fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21334    let tab_size = tab_size.get() as usize;
21335    let mut width = offset;
21336
21337    for ch in text.chars() {
21338        width += if ch == '\t' {
21339            tab_size - (width % tab_size)
21340        } else {
21341            1
21342        };
21343    }
21344
21345    width - offset
21346}
21347
21348#[cfg(test)]
21349mod tests {
21350    use super::*;
21351
21352    #[test]
21353    fn test_string_size_with_expanded_tabs() {
21354        let nz = |val| NonZeroU32::new(val).unwrap();
21355        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21356        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21357        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21358        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21359        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21360        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21361        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21362        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21363    }
21364}
21365
21366/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21367struct WordBreakingTokenizer<'a> {
21368    input: &'a str,
21369}
21370
21371impl<'a> WordBreakingTokenizer<'a> {
21372    fn new(input: &'a str) -> Self {
21373        Self { input }
21374    }
21375}
21376
21377fn is_char_ideographic(ch: char) -> bool {
21378    use unicode_script::Script::*;
21379    use unicode_script::UnicodeScript;
21380    matches!(ch.script(), Han | Tangut | Yi)
21381}
21382
21383fn is_grapheme_ideographic(text: &str) -> bool {
21384    text.chars().any(is_char_ideographic)
21385}
21386
21387fn is_grapheme_whitespace(text: &str) -> bool {
21388    text.chars().any(|x| x.is_whitespace())
21389}
21390
21391fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21392    text.chars().next().map_or(false, |ch| {
21393        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21394    })
21395}
21396
21397#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21398enum WordBreakToken<'a> {
21399    Word { token: &'a str, grapheme_len: usize },
21400    InlineWhitespace { token: &'a str, grapheme_len: usize },
21401    Newline,
21402}
21403
21404impl<'a> Iterator for WordBreakingTokenizer<'a> {
21405    /// Yields a span, the count of graphemes in the token, and whether it was
21406    /// whitespace. Note that it also breaks at word boundaries.
21407    type Item = WordBreakToken<'a>;
21408
21409    fn next(&mut self) -> Option<Self::Item> {
21410        use unicode_segmentation::UnicodeSegmentation;
21411        if self.input.is_empty() {
21412            return None;
21413        }
21414
21415        let mut iter = self.input.graphemes(true).peekable();
21416        let mut offset = 0;
21417        let mut grapheme_len = 0;
21418        if let Some(first_grapheme) = iter.next() {
21419            let is_newline = first_grapheme == "\n";
21420            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21421            offset += first_grapheme.len();
21422            grapheme_len += 1;
21423            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21424                if let Some(grapheme) = iter.peek().copied() {
21425                    if should_stay_with_preceding_ideograph(grapheme) {
21426                        offset += grapheme.len();
21427                        grapheme_len += 1;
21428                    }
21429                }
21430            } else {
21431                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21432                let mut next_word_bound = words.peek().copied();
21433                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21434                    next_word_bound = words.next();
21435                }
21436                while let Some(grapheme) = iter.peek().copied() {
21437                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21438                        break;
21439                    };
21440                    if is_grapheme_whitespace(grapheme) != is_whitespace
21441                        || (grapheme == "\n") != is_newline
21442                    {
21443                        break;
21444                    };
21445                    offset += grapheme.len();
21446                    grapheme_len += 1;
21447                    iter.next();
21448                }
21449            }
21450            let token = &self.input[..offset];
21451            self.input = &self.input[offset..];
21452            if token == "\n" {
21453                Some(WordBreakToken::Newline)
21454            } else if is_whitespace {
21455                Some(WordBreakToken::InlineWhitespace {
21456                    token,
21457                    grapheme_len,
21458                })
21459            } else {
21460                Some(WordBreakToken::Word {
21461                    token,
21462                    grapheme_len,
21463                })
21464            }
21465        } else {
21466            None
21467        }
21468    }
21469}
21470
21471#[test]
21472fn test_word_breaking_tokenizer() {
21473    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21474        ("", &[]),
21475        ("  ", &[whitespace("  ", 2)]),
21476        ("Ʒ", &[word("Ʒ", 1)]),
21477        ("Ǽ", &[word("Ǽ", 1)]),
21478        ("", &[word("", 1)]),
21479        ("⋑⋑", &[word("⋑⋑", 2)]),
21480        (
21481            "原理,进而",
21482            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21483        ),
21484        (
21485            "hello world",
21486            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21487        ),
21488        (
21489            "hello, world",
21490            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21491        ),
21492        (
21493            "  hello world",
21494            &[
21495                whitespace("  ", 2),
21496                word("hello", 5),
21497                whitespace(" ", 1),
21498                word("world", 5),
21499            ],
21500        ),
21501        (
21502            "这是什么 \n 钢笔",
21503            &[
21504                word("", 1),
21505                word("", 1),
21506                word("", 1),
21507                word("", 1),
21508                whitespace(" ", 1),
21509                newline(),
21510                whitespace(" ", 1),
21511                word("", 1),
21512                word("", 1),
21513            ],
21514        ),
21515        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21516    ];
21517
21518    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21519        WordBreakToken::Word {
21520            token,
21521            grapheme_len,
21522        }
21523    }
21524
21525    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21526        WordBreakToken::InlineWhitespace {
21527            token,
21528            grapheme_len,
21529        }
21530    }
21531
21532    fn newline() -> WordBreakToken<'static> {
21533        WordBreakToken::Newline
21534    }
21535
21536    for (input, result) in tests {
21537        assert_eq!(
21538            WordBreakingTokenizer::new(input)
21539                .collect::<Vec<_>>()
21540                .as_slice(),
21541            *result,
21542        );
21543    }
21544}
21545
21546fn wrap_with_prefix(
21547    first_line_prefix: String,
21548    subsequent_lines_prefix: String,
21549    unwrapped_text: String,
21550    wrap_column: usize,
21551    tab_size: NonZeroU32,
21552    preserve_existing_whitespace: bool,
21553) -> String {
21554    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21555    let subsequent_lines_prefix_len =
21556        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21557    let mut wrapped_text = String::new();
21558    let mut current_line = first_line_prefix.clone();
21559    let mut is_first_line = true;
21560
21561    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21562    let mut current_line_len = first_line_prefix_len;
21563    let mut in_whitespace = false;
21564    for token in tokenizer {
21565        let have_preceding_whitespace = in_whitespace;
21566        match token {
21567            WordBreakToken::Word {
21568                token,
21569                grapheme_len,
21570            } => {
21571                in_whitespace = false;
21572                let current_prefix_len = if is_first_line {
21573                    first_line_prefix_len
21574                } else {
21575                    subsequent_lines_prefix_len
21576                };
21577                if current_line_len + grapheme_len > wrap_column
21578                    && current_line_len != current_prefix_len
21579                {
21580                    wrapped_text.push_str(current_line.trim_end());
21581                    wrapped_text.push('\n');
21582                    is_first_line = false;
21583                    current_line = subsequent_lines_prefix.clone();
21584                    current_line_len = subsequent_lines_prefix_len;
21585                }
21586                current_line.push_str(token);
21587                current_line_len += grapheme_len;
21588            }
21589            WordBreakToken::InlineWhitespace {
21590                mut token,
21591                mut grapheme_len,
21592            } => {
21593                in_whitespace = true;
21594                if have_preceding_whitespace && !preserve_existing_whitespace {
21595                    continue;
21596                }
21597                if !preserve_existing_whitespace {
21598                    token = " ";
21599                    grapheme_len = 1;
21600                }
21601                let current_prefix_len = if is_first_line {
21602                    first_line_prefix_len
21603                } else {
21604                    subsequent_lines_prefix_len
21605                };
21606                if current_line_len + grapheme_len > wrap_column {
21607                    wrapped_text.push_str(current_line.trim_end());
21608                    wrapped_text.push('\n');
21609                    is_first_line = false;
21610                    current_line = subsequent_lines_prefix.clone();
21611                    current_line_len = subsequent_lines_prefix_len;
21612                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21613                    current_line.push_str(token);
21614                    current_line_len += grapheme_len;
21615                }
21616            }
21617            WordBreakToken::Newline => {
21618                in_whitespace = true;
21619                let current_prefix_len = if is_first_line {
21620                    first_line_prefix_len
21621                } else {
21622                    subsequent_lines_prefix_len
21623                };
21624                if preserve_existing_whitespace {
21625                    wrapped_text.push_str(current_line.trim_end());
21626                    wrapped_text.push('\n');
21627                    is_first_line = false;
21628                    current_line = subsequent_lines_prefix.clone();
21629                    current_line_len = subsequent_lines_prefix_len;
21630                } else if have_preceding_whitespace {
21631                    continue;
21632                } else if current_line_len + 1 > wrap_column
21633                    && current_line_len != current_prefix_len
21634                {
21635                    wrapped_text.push_str(current_line.trim_end());
21636                    wrapped_text.push('\n');
21637                    is_first_line = false;
21638                    current_line = subsequent_lines_prefix.clone();
21639                    current_line_len = subsequent_lines_prefix_len;
21640                } else if current_line_len != current_prefix_len {
21641                    current_line.push(' ');
21642                    current_line_len += 1;
21643                }
21644            }
21645        }
21646    }
21647
21648    if !current_line.is_empty() {
21649        wrapped_text.push_str(&current_line);
21650    }
21651    wrapped_text
21652}
21653
21654#[test]
21655fn test_wrap_with_prefix() {
21656    assert_eq!(
21657        wrap_with_prefix(
21658            "# ".to_string(),
21659            "# ".to_string(),
21660            "abcdefg".to_string(),
21661            4,
21662            NonZeroU32::new(4).unwrap(),
21663            false,
21664        ),
21665        "# abcdefg"
21666    );
21667    assert_eq!(
21668        wrap_with_prefix(
21669            "".to_string(),
21670            "".to_string(),
21671            "\thello world".to_string(),
21672            8,
21673            NonZeroU32::new(4).unwrap(),
21674            false,
21675        ),
21676        "hello\nworld"
21677    );
21678    assert_eq!(
21679        wrap_with_prefix(
21680            "// ".to_string(),
21681            "// ".to_string(),
21682            "xx \nyy zz aa bb cc".to_string(),
21683            12,
21684            NonZeroU32::new(4).unwrap(),
21685            false,
21686        ),
21687        "// xx yy zz\n// aa bb cc"
21688    );
21689    assert_eq!(
21690        wrap_with_prefix(
21691            String::new(),
21692            String::new(),
21693            "这是什么 \n 钢笔".to_string(),
21694            3,
21695            NonZeroU32::new(4).unwrap(),
21696            false,
21697        ),
21698        "这是什\n么 钢\n"
21699    );
21700}
21701
21702pub trait CollaborationHub {
21703    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21704    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21705    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21706}
21707
21708impl CollaborationHub for Entity<Project> {
21709    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21710        self.read(cx).collaborators()
21711    }
21712
21713    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21714        self.read(cx).user_store().read(cx).participant_indices()
21715    }
21716
21717    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21718        let this = self.read(cx);
21719        let user_ids = this.collaborators().values().map(|c| c.user_id);
21720        this.user_store().read(cx).participant_names(user_ids, cx)
21721    }
21722}
21723
21724pub trait SemanticsProvider {
21725    fn hover(
21726        &self,
21727        buffer: &Entity<Buffer>,
21728        position: text::Anchor,
21729        cx: &mut App,
21730    ) -> Option<Task<Vec<project::Hover>>>;
21731
21732    fn inline_values(
21733        &self,
21734        buffer_handle: Entity<Buffer>,
21735        range: Range<text::Anchor>,
21736        cx: &mut App,
21737    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21738
21739    fn inlay_hints(
21740        &self,
21741        buffer_handle: Entity<Buffer>,
21742        range: Range<text::Anchor>,
21743        cx: &mut App,
21744    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21745
21746    fn resolve_inlay_hint(
21747        &self,
21748        hint: InlayHint,
21749        buffer_handle: Entity<Buffer>,
21750        server_id: LanguageServerId,
21751        cx: &mut App,
21752    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21753
21754    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21755
21756    fn document_highlights(
21757        &self,
21758        buffer: &Entity<Buffer>,
21759        position: text::Anchor,
21760        cx: &mut App,
21761    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21762
21763    fn definitions(
21764        &self,
21765        buffer: &Entity<Buffer>,
21766        position: text::Anchor,
21767        kind: GotoDefinitionKind,
21768        cx: &mut App,
21769    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21770
21771    fn range_for_rename(
21772        &self,
21773        buffer: &Entity<Buffer>,
21774        position: text::Anchor,
21775        cx: &mut App,
21776    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21777
21778    fn perform_rename(
21779        &self,
21780        buffer: &Entity<Buffer>,
21781        position: text::Anchor,
21782        new_name: String,
21783        cx: &mut App,
21784    ) -> Option<Task<Result<ProjectTransaction>>>;
21785}
21786
21787pub trait CompletionProvider {
21788    fn completions(
21789        &self,
21790        excerpt_id: ExcerptId,
21791        buffer: &Entity<Buffer>,
21792        buffer_position: text::Anchor,
21793        trigger: CompletionContext,
21794        window: &mut Window,
21795        cx: &mut Context<Editor>,
21796    ) -> Task<Result<Vec<CompletionResponse>>>;
21797
21798    fn resolve_completions(
21799        &self,
21800        _buffer: Entity<Buffer>,
21801        _completion_indices: Vec<usize>,
21802        _completions: Rc<RefCell<Box<[Completion]>>>,
21803        _cx: &mut Context<Editor>,
21804    ) -> Task<Result<bool>> {
21805        Task::ready(Ok(false))
21806    }
21807
21808    fn apply_additional_edits_for_completion(
21809        &self,
21810        _buffer: Entity<Buffer>,
21811        _completions: Rc<RefCell<Box<[Completion]>>>,
21812        _completion_index: usize,
21813        _push_to_history: bool,
21814        _cx: &mut Context<Editor>,
21815    ) -> Task<Result<Option<language::Transaction>>> {
21816        Task::ready(Ok(None))
21817    }
21818
21819    fn is_completion_trigger(
21820        &self,
21821        buffer: &Entity<Buffer>,
21822        position: language::Anchor,
21823        text: &str,
21824        trigger_in_words: bool,
21825        menu_is_open: bool,
21826        cx: &mut Context<Editor>,
21827    ) -> bool;
21828
21829    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21830
21831    fn sort_completions(&self) -> bool {
21832        true
21833    }
21834
21835    fn filter_completions(&self) -> bool {
21836        true
21837    }
21838}
21839
21840pub trait CodeActionProvider {
21841    fn id(&self) -> Arc<str>;
21842
21843    fn code_actions(
21844        &self,
21845        buffer: &Entity<Buffer>,
21846        range: Range<text::Anchor>,
21847        window: &mut Window,
21848        cx: &mut App,
21849    ) -> Task<Result<Vec<CodeAction>>>;
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}
21861
21862impl CodeActionProvider for Entity<Project> {
21863    fn id(&self) -> Arc<str> {
21864        "project".into()
21865    }
21866
21867    fn code_actions(
21868        &self,
21869        buffer: &Entity<Buffer>,
21870        range: Range<text::Anchor>,
21871        _window: &mut Window,
21872        cx: &mut App,
21873    ) -> Task<Result<Vec<CodeAction>>> {
21874        self.update(cx, |project, cx| {
21875            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21876            let code_actions = project.code_actions(buffer, range, None, cx);
21877            cx.background_spawn(async move {
21878                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21879                Ok(code_lens_actions
21880                    .context("code lens fetch")?
21881                    .into_iter()
21882                    .chain(code_actions.context("code action fetch")?)
21883                    .collect())
21884            })
21885        })
21886    }
21887
21888    fn apply_code_action(
21889        &self,
21890        buffer_handle: Entity<Buffer>,
21891        action: CodeAction,
21892        _excerpt_id: ExcerptId,
21893        push_to_history: bool,
21894        _window: &mut Window,
21895        cx: &mut App,
21896    ) -> Task<Result<ProjectTransaction>> {
21897        self.update(cx, |project, cx| {
21898            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21899        })
21900    }
21901}
21902
21903fn snippet_completions(
21904    project: &Project,
21905    buffer: &Entity<Buffer>,
21906    buffer_position: text::Anchor,
21907    cx: &mut App,
21908) -> Task<Result<CompletionResponse>> {
21909    let languages = buffer.read(cx).languages_at(buffer_position);
21910    let snippet_store = project.snippets().read(cx);
21911
21912    let scopes: Vec<_> = languages
21913        .iter()
21914        .filter_map(|language| {
21915            let language_name = language.lsp_id();
21916            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21917
21918            if snippets.is_empty() {
21919                None
21920            } else {
21921                Some((language.default_scope(), snippets))
21922            }
21923        })
21924        .collect();
21925
21926    if scopes.is_empty() {
21927        return Task::ready(Ok(CompletionResponse {
21928            completions: vec![],
21929            is_incomplete: false,
21930        }));
21931    }
21932
21933    let snapshot = buffer.read(cx).text_snapshot();
21934    let chars: String = snapshot
21935        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21936        .collect();
21937    let executor = cx.background_executor().clone();
21938
21939    cx.background_spawn(async move {
21940        let mut is_incomplete = false;
21941        let mut completions: Vec<Completion> = Vec::new();
21942        for (scope, snippets) in scopes.into_iter() {
21943            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21944            let mut last_word = chars
21945                .chars()
21946                .take_while(|c| classifier.is_word(*c))
21947                .collect::<String>();
21948            last_word = last_word.chars().rev().collect();
21949
21950            if last_word.is_empty() {
21951                return Ok(CompletionResponse {
21952                    completions: vec![],
21953                    is_incomplete: true,
21954                });
21955            }
21956
21957            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21958            let to_lsp = |point: &text::Anchor| {
21959                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21960                point_to_lsp(end)
21961            };
21962            let lsp_end = to_lsp(&buffer_position);
21963
21964            let candidates = snippets
21965                .iter()
21966                .enumerate()
21967                .flat_map(|(ix, snippet)| {
21968                    snippet
21969                        .prefix
21970                        .iter()
21971                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21972                })
21973                .collect::<Vec<StringMatchCandidate>>();
21974
21975            const MAX_RESULTS: usize = 100;
21976            let mut matches = fuzzy::match_strings(
21977                &candidates,
21978                &last_word,
21979                last_word.chars().any(|c| c.is_uppercase()),
21980                true,
21981                MAX_RESULTS,
21982                &Default::default(),
21983                executor.clone(),
21984            )
21985            .await;
21986
21987            if matches.len() >= MAX_RESULTS {
21988                is_incomplete = true;
21989            }
21990
21991            // Remove all candidates where the query's start does not match the start of any word in the candidate
21992            if let Some(query_start) = last_word.chars().next() {
21993                matches.retain(|string_match| {
21994                    split_words(&string_match.string).any(|word| {
21995                        // Check that the first codepoint of the word as lowercase matches the first
21996                        // codepoint of the query as lowercase
21997                        word.chars()
21998                            .flat_map(|codepoint| codepoint.to_lowercase())
21999                            .zip(query_start.to_lowercase())
22000                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22001                    })
22002                });
22003            }
22004
22005            let matched_strings = matches
22006                .into_iter()
22007                .map(|m| m.string)
22008                .collect::<HashSet<_>>();
22009
22010            completions.extend(snippets.iter().filter_map(|snippet| {
22011                let matching_prefix = snippet
22012                    .prefix
22013                    .iter()
22014                    .find(|prefix| matched_strings.contains(*prefix))?;
22015                let start = as_offset - last_word.len();
22016                let start = snapshot.anchor_before(start);
22017                let range = start..buffer_position;
22018                let lsp_start = to_lsp(&start);
22019                let lsp_range = lsp::Range {
22020                    start: lsp_start,
22021                    end: lsp_end,
22022                };
22023                Some(Completion {
22024                    replace_range: range,
22025                    new_text: snippet.body.clone(),
22026                    source: CompletionSource::Lsp {
22027                        insert_range: None,
22028                        server_id: LanguageServerId(usize::MAX),
22029                        resolved: true,
22030                        lsp_completion: Box::new(lsp::CompletionItem {
22031                            label: snippet.prefix.first().unwrap().clone(),
22032                            kind: Some(CompletionItemKind::SNIPPET),
22033                            label_details: snippet.description.as_ref().map(|description| {
22034                                lsp::CompletionItemLabelDetails {
22035                                    detail: Some(description.clone()),
22036                                    description: None,
22037                                }
22038                            }),
22039                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22040                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22041                                lsp::InsertReplaceEdit {
22042                                    new_text: snippet.body.clone(),
22043                                    insert: lsp_range,
22044                                    replace: lsp_range,
22045                                },
22046                            )),
22047                            filter_text: Some(snippet.body.clone()),
22048                            sort_text: Some(char::MAX.to_string()),
22049                            ..lsp::CompletionItem::default()
22050                        }),
22051                        lsp_defaults: None,
22052                    },
22053                    label: CodeLabel {
22054                        text: matching_prefix.clone(),
22055                        runs: Vec::new(),
22056                        filter_range: 0..matching_prefix.len(),
22057                    },
22058                    icon_path: None,
22059                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22060                        single_line: snippet.name.clone().into(),
22061                        plain_text: snippet
22062                            .description
22063                            .clone()
22064                            .map(|description| description.into()),
22065                    }),
22066                    insert_text_mode: None,
22067                    confirm: None,
22068                })
22069            }))
22070        }
22071
22072        Ok(CompletionResponse {
22073            completions,
22074            is_incomplete,
22075        })
22076    })
22077}
22078
22079impl CompletionProvider for Entity<Project> {
22080    fn completions(
22081        &self,
22082        _excerpt_id: ExcerptId,
22083        buffer: &Entity<Buffer>,
22084        buffer_position: text::Anchor,
22085        options: CompletionContext,
22086        _window: &mut Window,
22087        cx: &mut Context<Editor>,
22088    ) -> Task<Result<Vec<CompletionResponse>>> {
22089        self.update(cx, |project, cx| {
22090            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22091            let project_completions = project.completions(buffer, buffer_position, options, cx);
22092            cx.background_spawn(async move {
22093                let mut responses = project_completions.await?;
22094                let snippets = snippets.await?;
22095                if !snippets.completions.is_empty() {
22096                    responses.push(snippets);
22097                }
22098                Ok(responses)
22099            })
22100        })
22101    }
22102
22103    fn resolve_completions(
22104        &self,
22105        buffer: Entity<Buffer>,
22106        completion_indices: Vec<usize>,
22107        completions: Rc<RefCell<Box<[Completion]>>>,
22108        cx: &mut Context<Editor>,
22109    ) -> Task<Result<bool>> {
22110        self.update(cx, |project, cx| {
22111            project.lsp_store().update(cx, |lsp_store, cx| {
22112                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22113            })
22114        })
22115    }
22116
22117    fn apply_additional_edits_for_completion(
22118        &self,
22119        buffer: Entity<Buffer>,
22120        completions: Rc<RefCell<Box<[Completion]>>>,
22121        completion_index: usize,
22122        push_to_history: bool,
22123        cx: &mut Context<Editor>,
22124    ) -> Task<Result<Option<language::Transaction>>> {
22125        self.update(cx, |project, cx| {
22126            project.lsp_store().update(cx, |lsp_store, cx| {
22127                lsp_store.apply_additional_edits_for_completion(
22128                    buffer,
22129                    completions,
22130                    completion_index,
22131                    push_to_history,
22132                    cx,
22133                )
22134            })
22135        })
22136    }
22137
22138    fn is_completion_trigger(
22139        &self,
22140        buffer: &Entity<Buffer>,
22141        position: language::Anchor,
22142        text: &str,
22143        trigger_in_words: bool,
22144        menu_is_open: bool,
22145        cx: &mut Context<Editor>,
22146    ) -> bool {
22147        let mut chars = text.chars();
22148        let char = if let Some(char) = chars.next() {
22149            char
22150        } else {
22151            return false;
22152        };
22153        if chars.next().is_some() {
22154            return false;
22155        }
22156
22157        let buffer = buffer.read(cx);
22158        let snapshot = buffer.snapshot();
22159        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22160            return false;
22161        }
22162        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22163        if trigger_in_words && classifier.is_word(char) {
22164            return true;
22165        }
22166
22167        buffer.completion_triggers().contains(text)
22168    }
22169}
22170
22171impl SemanticsProvider for Entity<Project> {
22172    fn hover(
22173        &self,
22174        buffer: &Entity<Buffer>,
22175        position: text::Anchor,
22176        cx: &mut App,
22177    ) -> Option<Task<Vec<project::Hover>>> {
22178        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22179    }
22180
22181    fn document_highlights(
22182        &self,
22183        buffer: &Entity<Buffer>,
22184        position: text::Anchor,
22185        cx: &mut App,
22186    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22187        Some(self.update(cx, |project, cx| {
22188            project.document_highlights(buffer, position, cx)
22189        }))
22190    }
22191
22192    fn definitions(
22193        &self,
22194        buffer: &Entity<Buffer>,
22195        position: text::Anchor,
22196        kind: GotoDefinitionKind,
22197        cx: &mut App,
22198    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22199        Some(self.update(cx, |project, cx| match kind {
22200            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22201            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22202            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22203            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22204        }))
22205    }
22206
22207    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22208        // TODO: make this work for remote projects
22209        self.update(cx, |project, cx| {
22210            if project
22211                .active_debug_session(cx)
22212                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22213            {
22214                return true;
22215            }
22216
22217            buffer.update(cx, |buffer, cx| {
22218                project.any_language_server_supports_inlay_hints(buffer, cx)
22219            })
22220        })
22221    }
22222
22223    fn inline_values(
22224        &self,
22225        buffer_handle: Entity<Buffer>,
22226        range: Range<text::Anchor>,
22227        cx: &mut App,
22228    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22229        self.update(cx, |project, cx| {
22230            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22231
22232            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22233        })
22234    }
22235
22236    fn inlay_hints(
22237        &self,
22238        buffer_handle: Entity<Buffer>,
22239        range: Range<text::Anchor>,
22240        cx: &mut App,
22241    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22242        Some(self.update(cx, |project, cx| {
22243            project.inlay_hints(buffer_handle, range, cx)
22244        }))
22245    }
22246
22247    fn resolve_inlay_hint(
22248        &self,
22249        hint: InlayHint,
22250        buffer_handle: Entity<Buffer>,
22251        server_id: LanguageServerId,
22252        cx: &mut App,
22253    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22254        Some(self.update(cx, |project, cx| {
22255            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22256        }))
22257    }
22258
22259    fn range_for_rename(
22260        &self,
22261        buffer: &Entity<Buffer>,
22262        position: text::Anchor,
22263        cx: &mut App,
22264    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22265        Some(self.update(cx, |project, cx| {
22266            let buffer = buffer.clone();
22267            let task = project.prepare_rename(buffer.clone(), position, cx);
22268            cx.spawn(async move |_, cx| {
22269                Ok(match task.await? {
22270                    PrepareRenameResponse::Success(range) => Some(range),
22271                    PrepareRenameResponse::InvalidPosition => None,
22272                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22273                        // Fallback on using TreeSitter info to determine identifier range
22274                        buffer.read_with(cx, |buffer, _| {
22275                            let snapshot = buffer.snapshot();
22276                            let (range, kind) = snapshot.surrounding_word(position, false);
22277                            if kind != Some(CharKind::Word) {
22278                                return None;
22279                            }
22280                            Some(
22281                                snapshot.anchor_before(range.start)
22282                                    ..snapshot.anchor_after(range.end),
22283                            )
22284                        })?
22285                    }
22286                })
22287            })
22288        }))
22289    }
22290
22291    fn perform_rename(
22292        &self,
22293        buffer: &Entity<Buffer>,
22294        position: text::Anchor,
22295        new_name: String,
22296        cx: &mut App,
22297    ) -> Option<Task<Result<ProjectTransaction>>> {
22298        Some(self.update(cx, |project, cx| {
22299            project.perform_rename(buffer.clone(), position, new_name, cx)
22300        }))
22301    }
22302}
22303
22304fn inlay_hint_settings(
22305    location: Anchor,
22306    snapshot: &MultiBufferSnapshot,
22307    cx: &mut Context<Editor>,
22308) -> InlayHintSettings {
22309    let file = snapshot.file_at(location);
22310    let language = snapshot.language_at(location).map(|l| l.name());
22311    language_settings(language, file, cx).inlay_hints
22312}
22313
22314fn consume_contiguous_rows(
22315    contiguous_row_selections: &mut Vec<Selection<Point>>,
22316    selection: &Selection<Point>,
22317    display_map: &DisplaySnapshot,
22318    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22319) -> (MultiBufferRow, MultiBufferRow) {
22320    contiguous_row_selections.push(selection.clone());
22321    let start_row = starting_row(selection, display_map);
22322    let mut end_row = ending_row(selection, display_map);
22323
22324    while let Some(next_selection) = selections.peek() {
22325        if next_selection.start.row <= end_row.0 {
22326            end_row = ending_row(next_selection, display_map);
22327            contiguous_row_selections.push(selections.next().unwrap().clone());
22328        } else {
22329            break;
22330        }
22331    }
22332    (start_row, end_row)
22333}
22334
22335fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22336    if selection.start.column > 0 {
22337        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22338    } else {
22339        MultiBufferRow(selection.start.row)
22340    }
22341}
22342
22343fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22344    if next_selection.end.column > 0 || next_selection.is_empty() {
22345        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22346    } else {
22347        MultiBufferRow(next_selection.end.row)
22348    }
22349}
22350
22351impl EditorSnapshot {
22352    pub fn remote_selections_in_range<'a>(
22353        &'a self,
22354        range: &'a Range<Anchor>,
22355        collaboration_hub: &dyn CollaborationHub,
22356        cx: &'a App,
22357    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22358        let participant_names = collaboration_hub.user_names(cx);
22359        let participant_indices = collaboration_hub.user_participant_indices(cx);
22360        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22361        let collaborators_by_replica_id = collaborators_by_peer_id
22362            .values()
22363            .map(|collaborator| (collaborator.replica_id, collaborator))
22364            .collect::<HashMap<_, _>>();
22365        self.buffer_snapshot
22366            .selections_in_range(range, false)
22367            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22368                if replica_id == AGENT_REPLICA_ID {
22369                    Some(RemoteSelection {
22370                        replica_id,
22371                        selection,
22372                        cursor_shape,
22373                        line_mode,
22374                        collaborator_id: CollaboratorId::Agent,
22375                        user_name: Some("Agent".into()),
22376                        color: cx.theme().players().agent(),
22377                    })
22378                } else {
22379                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22380                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22381                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22382                    Some(RemoteSelection {
22383                        replica_id,
22384                        selection,
22385                        cursor_shape,
22386                        line_mode,
22387                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22388                        user_name,
22389                        color: if let Some(index) = participant_index {
22390                            cx.theme().players().color_for_participant(index.0)
22391                        } else {
22392                            cx.theme().players().absent()
22393                        },
22394                    })
22395                }
22396            })
22397    }
22398
22399    pub fn hunks_for_ranges(
22400        &self,
22401        ranges: impl IntoIterator<Item = Range<Point>>,
22402    ) -> Vec<MultiBufferDiffHunk> {
22403        let mut hunks = Vec::new();
22404        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22405            HashMap::default();
22406        for query_range in ranges {
22407            let query_rows =
22408                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22409            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22410                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22411            ) {
22412                // Include deleted hunks that are adjacent to the query range, because
22413                // otherwise they would be missed.
22414                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22415                if hunk.status().is_deleted() {
22416                    intersects_range |= hunk.row_range.start == query_rows.end;
22417                    intersects_range |= hunk.row_range.end == query_rows.start;
22418                }
22419                if intersects_range {
22420                    if !processed_buffer_rows
22421                        .entry(hunk.buffer_id)
22422                        .or_default()
22423                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22424                    {
22425                        continue;
22426                    }
22427                    hunks.push(hunk);
22428                }
22429            }
22430        }
22431
22432        hunks
22433    }
22434
22435    fn display_diff_hunks_for_rows<'a>(
22436        &'a self,
22437        display_rows: Range<DisplayRow>,
22438        folded_buffers: &'a HashSet<BufferId>,
22439    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22440        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22441        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22442
22443        self.buffer_snapshot
22444            .diff_hunks_in_range(buffer_start..buffer_end)
22445            .filter_map(|hunk| {
22446                if folded_buffers.contains(&hunk.buffer_id) {
22447                    return None;
22448                }
22449
22450                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22451                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22452
22453                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22454                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22455
22456                let display_hunk = if hunk_display_start.column() != 0 {
22457                    DisplayDiffHunk::Folded {
22458                        display_row: hunk_display_start.row(),
22459                    }
22460                } else {
22461                    let mut end_row = hunk_display_end.row();
22462                    if hunk_display_end.column() > 0 {
22463                        end_row.0 += 1;
22464                    }
22465                    let is_created_file = hunk.is_created_file();
22466                    DisplayDiffHunk::Unfolded {
22467                        status: hunk.status(),
22468                        diff_base_byte_range: hunk.diff_base_byte_range,
22469                        display_row_range: hunk_display_start.row()..end_row,
22470                        multi_buffer_range: Anchor::range_in_buffer(
22471                            hunk.excerpt_id,
22472                            hunk.buffer_id,
22473                            hunk.buffer_range,
22474                        ),
22475                        is_created_file,
22476                    }
22477                };
22478
22479                Some(display_hunk)
22480            })
22481    }
22482
22483    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22484        self.display_snapshot.buffer_snapshot.language_at(position)
22485    }
22486
22487    pub fn is_focused(&self) -> bool {
22488        self.is_focused
22489    }
22490
22491    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22492        self.placeholder_text.as_ref()
22493    }
22494
22495    pub fn scroll_position(&self) -> gpui::Point<f32> {
22496        self.scroll_anchor.scroll_position(&self.display_snapshot)
22497    }
22498
22499    fn gutter_dimensions(
22500        &self,
22501        font_id: FontId,
22502        font_size: Pixels,
22503        max_line_number_width: Pixels,
22504        cx: &App,
22505    ) -> Option<GutterDimensions> {
22506        if !self.show_gutter {
22507            return None;
22508        }
22509
22510        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22511        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22512
22513        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22514            matches!(
22515                ProjectSettings::get_global(cx).git.git_gutter,
22516                Some(GitGutterSetting::TrackedFiles)
22517            )
22518        });
22519        let gutter_settings = EditorSettings::get_global(cx).gutter;
22520        let show_line_numbers = self
22521            .show_line_numbers
22522            .unwrap_or(gutter_settings.line_numbers);
22523        let line_gutter_width = if show_line_numbers {
22524            // Avoid flicker-like gutter resizes when the line number gains another digit by
22525            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22526            let min_width_for_number_on_gutter =
22527                ch_advance * gutter_settings.min_line_number_digits as f32;
22528            max_line_number_width.max(min_width_for_number_on_gutter)
22529        } else {
22530            0.0.into()
22531        };
22532
22533        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22534        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22535
22536        let git_blame_entries_width =
22537            self.git_blame_gutter_max_author_length
22538                .map(|max_author_length| {
22539                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22540                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22541
22542                    /// The number of characters to dedicate to gaps and margins.
22543                    const SPACING_WIDTH: usize = 4;
22544
22545                    let max_char_count = max_author_length.min(renderer.max_author_length())
22546                        + ::git::SHORT_SHA_LENGTH
22547                        + MAX_RELATIVE_TIMESTAMP.len()
22548                        + SPACING_WIDTH;
22549
22550                    ch_advance * max_char_count
22551                });
22552
22553        let is_singleton = self.buffer_snapshot.is_singleton();
22554
22555        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22556        left_padding += if !is_singleton {
22557            ch_width * 4.0
22558        } else if show_runnables || show_breakpoints {
22559            ch_width * 3.0
22560        } else if show_git_gutter && show_line_numbers {
22561            ch_width * 2.0
22562        } else if show_git_gutter || show_line_numbers {
22563            ch_width
22564        } else {
22565            px(0.)
22566        };
22567
22568        let shows_folds = is_singleton && gutter_settings.folds;
22569
22570        let right_padding = if shows_folds && show_line_numbers {
22571            ch_width * 4.0
22572        } else if shows_folds || (!is_singleton && show_line_numbers) {
22573            ch_width * 3.0
22574        } else if show_line_numbers {
22575            ch_width
22576        } else {
22577            px(0.)
22578        };
22579
22580        Some(GutterDimensions {
22581            left_padding,
22582            right_padding,
22583            width: line_gutter_width + left_padding + right_padding,
22584            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22585            git_blame_entries_width,
22586        })
22587    }
22588
22589    pub fn render_crease_toggle(
22590        &self,
22591        buffer_row: MultiBufferRow,
22592        row_contains_cursor: bool,
22593        editor: Entity<Editor>,
22594        window: &mut Window,
22595        cx: &mut App,
22596    ) -> Option<AnyElement> {
22597        let folded = self.is_line_folded(buffer_row);
22598        let mut is_foldable = false;
22599
22600        if let Some(crease) = self
22601            .crease_snapshot
22602            .query_row(buffer_row, &self.buffer_snapshot)
22603        {
22604            is_foldable = true;
22605            match crease {
22606                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22607                    if let Some(render_toggle) = render_toggle {
22608                        let toggle_callback =
22609                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22610                                if folded {
22611                                    editor.update(cx, |editor, cx| {
22612                                        editor.fold_at(buffer_row, window, cx)
22613                                    });
22614                                } else {
22615                                    editor.update(cx, |editor, cx| {
22616                                        editor.unfold_at(buffer_row, window, cx)
22617                                    });
22618                                }
22619                            });
22620                        return Some((render_toggle)(
22621                            buffer_row,
22622                            folded,
22623                            toggle_callback,
22624                            window,
22625                            cx,
22626                        ));
22627                    }
22628                }
22629            }
22630        }
22631
22632        is_foldable |= self.starts_indent(buffer_row);
22633
22634        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22635            Some(
22636                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22637                    .toggle_state(folded)
22638                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22639                        if folded {
22640                            this.unfold_at(buffer_row, window, cx);
22641                        } else {
22642                            this.fold_at(buffer_row, window, cx);
22643                        }
22644                    }))
22645                    .into_any_element(),
22646            )
22647        } else {
22648            None
22649        }
22650    }
22651
22652    pub fn render_crease_trailer(
22653        &self,
22654        buffer_row: MultiBufferRow,
22655        window: &mut Window,
22656        cx: &mut App,
22657    ) -> Option<AnyElement> {
22658        let folded = self.is_line_folded(buffer_row);
22659        if let Crease::Inline { render_trailer, .. } = self
22660            .crease_snapshot
22661            .query_row(buffer_row, &self.buffer_snapshot)?
22662        {
22663            let render_trailer = render_trailer.as_ref()?;
22664            Some(render_trailer(buffer_row, folded, window, cx))
22665        } else {
22666            None
22667        }
22668    }
22669}
22670
22671impl Deref for EditorSnapshot {
22672    type Target = DisplaySnapshot;
22673
22674    fn deref(&self) -> &Self::Target {
22675        &self.display_snapshot
22676    }
22677}
22678
22679#[derive(Clone, Debug, PartialEq, Eq)]
22680pub enum EditorEvent {
22681    InputIgnored {
22682        text: Arc<str>,
22683    },
22684    InputHandled {
22685        utf16_range_to_replace: Option<Range<isize>>,
22686        text: Arc<str>,
22687    },
22688    ExcerptsAdded {
22689        buffer: Entity<Buffer>,
22690        predecessor: ExcerptId,
22691        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22692    },
22693    ExcerptsRemoved {
22694        ids: Vec<ExcerptId>,
22695        removed_buffer_ids: Vec<BufferId>,
22696    },
22697    BufferFoldToggled {
22698        ids: Vec<ExcerptId>,
22699        folded: bool,
22700    },
22701    ExcerptsEdited {
22702        ids: Vec<ExcerptId>,
22703    },
22704    ExcerptsExpanded {
22705        ids: Vec<ExcerptId>,
22706    },
22707    BufferEdited,
22708    Edited {
22709        transaction_id: clock::Lamport,
22710    },
22711    Reparsed(BufferId),
22712    Focused,
22713    FocusedIn,
22714    Blurred,
22715    DirtyChanged,
22716    Saved,
22717    TitleChanged,
22718    DiffBaseChanged,
22719    SelectionsChanged {
22720        local: bool,
22721    },
22722    ScrollPositionChanged {
22723        local: bool,
22724        autoscroll: bool,
22725    },
22726    Closed,
22727    TransactionUndone {
22728        transaction_id: clock::Lamport,
22729    },
22730    TransactionBegun {
22731        transaction_id: clock::Lamport,
22732    },
22733    Reloaded,
22734    CursorShapeChanged,
22735    PushedToNavHistory {
22736        anchor: Anchor,
22737        is_deactivate: bool,
22738    },
22739}
22740
22741impl EventEmitter<EditorEvent> for Editor {}
22742
22743impl Focusable for Editor {
22744    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22745        self.focus_handle.clone()
22746    }
22747}
22748
22749impl Render for Editor {
22750    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22751        let settings = ThemeSettings::get_global(cx);
22752
22753        let mut text_style = match self.mode {
22754            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22755                color: cx.theme().colors().editor_foreground,
22756                font_family: settings.ui_font.family.clone(),
22757                font_features: settings.ui_font.features.clone(),
22758                font_fallbacks: settings.ui_font.fallbacks.clone(),
22759                font_size: rems(0.875).into(),
22760                font_weight: settings.ui_font.weight,
22761                line_height: relative(settings.buffer_line_height.value()),
22762                ..Default::default()
22763            },
22764            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22765                color: cx.theme().colors().editor_foreground,
22766                font_family: settings.buffer_font.family.clone(),
22767                font_features: settings.buffer_font.features.clone(),
22768                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22769                font_size: settings.buffer_font_size(cx).into(),
22770                font_weight: settings.buffer_font.weight,
22771                line_height: relative(settings.buffer_line_height.value()),
22772                ..Default::default()
22773            },
22774        };
22775        if let Some(text_style_refinement) = &self.text_style_refinement {
22776            text_style.refine(text_style_refinement)
22777        }
22778
22779        let background = match self.mode {
22780            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22781            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22782            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22783            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22784        };
22785
22786        EditorElement::new(
22787            &cx.entity(),
22788            EditorStyle {
22789                background,
22790                border: cx.theme().colors().border,
22791                local_player: cx.theme().players().local(),
22792                text: text_style,
22793                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22794                syntax: cx.theme().syntax().clone(),
22795                status: cx.theme().status().clone(),
22796                inlay_hints_style: make_inlay_hints_style(cx),
22797                inline_completion_styles: make_suggestion_styles(cx),
22798                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22799                show_underlines: self.diagnostics_enabled(),
22800            },
22801        )
22802    }
22803}
22804
22805impl EntityInputHandler for Editor {
22806    fn text_for_range(
22807        &mut self,
22808        range_utf16: Range<usize>,
22809        adjusted_range: &mut Option<Range<usize>>,
22810        _: &mut Window,
22811        cx: &mut Context<Self>,
22812    ) -> Option<String> {
22813        let snapshot = self.buffer.read(cx).read(cx);
22814        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22815        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22816        if (start.0..end.0) != range_utf16 {
22817            adjusted_range.replace(start.0..end.0);
22818        }
22819        Some(snapshot.text_for_range(start..end).collect())
22820    }
22821
22822    fn selected_text_range(
22823        &mut self,
22824        ignore_disabled_input: bool,
22825        _: &mut Window,
22826        cx: &mut Context<Self>,
22827    ) -> Option<UTF16Selection> {
22828        // Prevent the IME menu from appearing when holding down an alphabetic key
22829        // while input is disabled.
22830        if !ignore_disabled_input && !self.input_enabled {
22831            return None;
22832        }
22833
22834        let selection = self.selections.newest::<OffsetUtf16>(cx);
22835        let range = selection.range();
22836
22837        Some(UTF16Selection {
22838            range: range.start.0..range.end.0,
22839            reversed: selection.reversed,
22840        })
22841    }
22842
22843    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22844        let snapshot = self.buffer.read(cx).read(cx);
22845        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22846        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22847    }
22848
22849    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22850        self.clear_highlights::<InputComposition>(cx);
22851        self.ime_transaction.take();
22852    }
22853
22854    fn replace_text_in_range(
22855        &mut self,
22856        range_utf16: Option<Range<usize>>,
22857        text: &str,
22858        window: &mut Window,
22859        cx: &mut Context<Self>,
22860    ) {
22861        if !self.input_enabled {
22862            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22863            return;
22864        }
22865
22866        self.transact(window, cx, |this, window, cx| {
22867            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22868                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22869                Some(this.selection_replacement_ranges(range_utf16, cx))
22870            } else {
22871                this.marked_text_ranges(cx)
22872            };
22873
22874            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22875                let newest_selection_id = this.selections.newest_anchor().id;
22876                this.selections
22877                    .all::<OffsetUtf16>(cx)
22878                    .iter()
22879                    .zip(ranges_to_replace.iter())
22880                    .find_map(|(selection, range)| {
22881                        if selection.id == newest_selection_id {
22882                            Some(
22883                                (range.start.0 as isize - selection.head().0 as isize)
22884                                    ..(range.end.0 as isize - selection.head().0 as isize),
22885                            )
22886                        } else {
22887                            None
22888                        }
22889                    })
22890            });
22891
22892            cx.emit(EditorEvent::InputHandled {
22893                utf16_range_to_replace: range_to_replace,
22894                text: text.into(),
22895            });
22896
22897            if let Some(new_selected_ranges) = new_selected_ranges {
22898                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22899                    selections.select_ranges(new_selected_ranges)
22900                });
22901                this.backspace(&Default::default(), window, cx);
22902            }
22903
22904            this.handle_input(text, window, cx);
22905        });
22906
22907        if let Some(transaction) = self.ime_transaction {
22908            self.buffer.update(cx, |buffer, cx| {
22909                buffer.group_until_transaction(transaction, cx);
22910            });
22911        }
22912
22913        self.unmark_text(window, cx);
22914    }
22915
22916    fn replace_and_mark_text_in_range(
22917        &mut self,
22918        range_utf16: Option<Range<usize>>,
22919        text: &str,
22920        new_selected_range_utf16: Option<Range<usize>>,
22921        window: &mut Window,
22922        cx: &mut Context<Self>,
22923    ) {
22924        if !self.input_enabled {
22925            return;
22926        }
22927
22928        let transaction = self.transact(window, cx, |this, window, cx| {
22929            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22930                let snapshot = this.buffer.read(cx).read(cx);
22931                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22932                    for marked_range in &mut marked_ranges {
22933                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22934                        marked_range.start.0 += relative_range_utf16.start;
22935                        marked_range.start =
22936                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22937                        marked_range.end =
22938                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22939                    }
22940                }
22941                Some(marked_ranges)
22942            } else if let Some(range_utf16) = range_utf16 {
22943                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22944                Some(this.selection_replacement_ranges(range_utf16, cx))
22945            } else {
22946                None
22947            };
22948
22949            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22950                let newest_selection_id = this.selections.newest_anchor().id;
22951                this.selections
22952                    .all::<OffsetUtf16>(cx)
22953                    .iter()
22954                    .zip(ranges_to_replace.iter())
22955                    .find_map(|(selection, range)| {
22956                        if selection.id == newest_selection_id {
22957                            Some(
22958                                (range.start.0 as isize - selection.head().0 as isize)
22959                                    ..(range.end.0 as isize - selection.head().0 as isize),
22960                            )
22961                        } else {
22962                            None
22963                        }
22964                    })
22965            });
22966
22967            cx.emit(EditorEvent::InputHandled {
22968                utf16_range_to_replace: range_to_replace,
22969                text: text.into(),
22970            });
22971
22972            if let Some(ranges) = ranges_to_replace {
22973                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22974                    s.select_ranges(ranges)
22975                });
22976            }
22977
22978            let marked_ranges = {
22979                let snapshot = this.buffer.read(cx).read(cx);
22980                this.selections
22981                    .disjoint_anchors()
22982                    .iter()
22983                    .map(|selection| {
22984                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22985                    })
22986                    .collect::<Vec<_>>()
22987            };
22988
22989            if text.is_empty() {
22990                this.unmark_text(window, cx);
22991            } else {
22992                this.highlight_text::<InputComposition>(
22993                    marked_ranges.clone(),
22994                    HighlightStyle {
22995                        underline: Some(UnderlineStyle {
22996                            thickness: px(1.),
22997                            color: None,
22998                            wavy: false,
22999                        }),
23000                        ..Default::default()
23001                    },
23002                    cx,
23003                );
23004            }
23005
23006            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23007            let use_autoclose = this.use_autoclose;
23008            let use_auto_surround = this.use_auto_surround;
23009            this.set_use_autoclose(false);
23010            this.set_use_auto_surround(false);
23011            this.handle_input(text, window, cx);
23012            this.set_use_autoclose(use_autoclose);
23013            this.set_use_auto_surround(use_auto_surround);
23014
23015            if let Some(new_selected_range) = new_selected_range_utf16 {
23016                let snapshot = this.buffer.read(cx).read(cx);
23017                let new_selected_ranges = marked_ranges
23018                    .into_iter()
23019                    .map(|marked_range| {
23020                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23021                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23022                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23023                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23024                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23025                    })
23026                    .collect::<Vec<_>>();
23027
23028                drop(snapshot);
23029                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23030                    selections.select_ranges(new_selected_ranges)
23031                });
23032            }
23033        });
23034
23035        self.ime_transaction = self.ime_transaction.or(transaction);
23036        if let Some(transaction) = self.ime_transaction {
23037            self.buffer.update(cx, |buffer, cx| {
23038                buffer.group_until_transaction(transaction, cx);
23039            });
23040        }
23041
23042        if self.text_highlights::<InputComposition>(cx).is_none() {
23043            self.ime_transaction.take();
23044        }
23045    }
23046
23047    fn bounds_for_range(
23048        &mut self,
23049        range_utf16: Range<usize>,
23050        element_bounds: gpui::Bounds<Pixels>,
23051        window: &mut Window,
23052        cx: &mut Context<Self>,
23053    ) -> Option<gpui::Bounds<Pixels>> {
23054        let text_layout_details = self.text_layout_details(window);
23055        let CharacterDimensions {
23056            em_width,
23057            em_advance,
23058            line_height,
23059        } = self.character_dimensions(window);
23060
23061        let snapshot = self.snapshot(window, cx);
23062        let scroll_position = snapshot.scroll_position();
23063        let scroll_left = scroll_position.x * em_advance;
23064
23065        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23066        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23067            + self.gutter_dimensions.full_width();
23068        let y = line_height * (start.row().as_f32() - scroll_position.y);
23069
23070        Some(Bounds {
23071            origin: element_bounds.origin + point(x, y),
23072            size: size(em_width, line_height),
23073        })
23074    }
23075
23076    fn character_index_for_point(
23077        &mut self,
23078        point: gpui::Point<Pixels>,
23079        _window: &mut Window,
23080        _cx: &mut Context<Self>,
23081    ) -> Option<usize> {
23082        let position_map = self.last_position_map.as_ref()?;
23083        if !position_map.text_hitbox.contains(&point) {
23084            return None;
23085        }
23086        let display_point = position_map.point_for_position(point).previous_valid;
23087        let anchor = position_map
23088            .snapshot
23089            .display_point_to_anchor(display_point, Bias::Left);
23090        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23091        Some(utf16_offset.0)
23092    }
23093}
23094
23095trait SelectionExt {
23096    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23097    fn spanned_rows(
23098        &self,
23099        include_end_if_at_line_start: bool,
23100        map: &DisplaySnapshot,
23101    ) -> Range<MultiBufferRow>;
23102}
23103
23104impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23105    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23106        let start = self
23107            .start
23108            .to_point(&map.buffer_snapshot)
23109            .to_display_point(map);
23110        let end = self
23111            .end
23112            .to_point(&map.buffer_snapshot)
23113            .to_display_point(map);
23114        if self.reversed {
23115            end..start
23116        } else {
23117            start..end
23118        }
23119    }
23120
23121    fn spanned_rows(
23122        &self,
23123        include_end_if_at_line_start: bool,
23124        map: &DisplaySnapshot,
23125    ) -> Range<MultiBufferRow> {
23126        let start = self.start.to_point(&map.buffer_snapshot);
23127        let mut end = self.end.to_point(&map.buffer_snapshot);
23128        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23129            end.row -= 1;
23130        }
23131
23132        let buffer_start = map.prev_line_boundary(start).0;
23133        let buffer_end = map.next_line_boundary(end).0;
23134        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23135    }
23136}
23137
23138impl<T: InvalidationRegion> InvalidationStack<T> {
23139    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23140    where
23141        S: Clone + ToOffset,
23142    {
23143        while let Some(region) = self.last() {
23144            let all_selections_inside_invalidation_ranges =
23145                if selections.len() == region.ranges().len() {
23146                    selections
23147                        .iter()
23148                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23149                        .all(|(selection, invalidation_range)| {
23150                            let head = selection.head().to_offset(buffer);
23151                            invalidation_range.start <= head && invalidation_range.end >= head
23152                        })
23153                } else {
23154                    false
23155                };
23156
23157            if all_selections_inside_invalidation_ranges {
23158                break;
23159            } else {
23160                self.pop();
23161            }
23162        }
23163    }
23164}
23165
23166impl<T> Default for InvalidationStack<T> {
23167    fn default() -> Self {
23168        Self(Default::default())
23169    }
23170}
23171
23172impl<T> Deref for InvalidationStack<T> {
23173    type Target = Vec<T>;
23174
23175    fn deref(&self) -> &Self::Target {
23176        &self.0
23177    }
23178}
23179
23180impl<T> DerefMut for InvalidationStack<T> {
23181    fn deref_mut(&mut self) -> &mut Self::Target {
23182        &mut self.0
23183    }
23184}
23185
23186impl InvalidationRegion for SnippetState {
23187    fn ranges(&self) -> &[Range<Anchor>] {
23188        &self.ranges[self.active_index]
23189    }
23190}
23191
23192fn inline_completion_edit_text(
23193    current_snapshot: &BufferSnapshot,
23194    edits: &[(Range<Anchor>, String)],
23195    edit_preview: &EditPreview,
23196    include_deletions: bool,
23197    cx: &App,
23198) -> HighlightedText {
23199    let edits = edits
23200        .iter()
23201        .map(|(anchor, text)| {
23202            (
23203                anchor.start.text_anchor..anchor.end.text_anchor,
23204                text.clone(),
23205            )
23206        })
23207        .collect::<Vec<_>>();
23208
23209    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23210}
23211
23212pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23213    match severity {
23214        lsp::DiagnosticSeverity::ERROR => colors.error,
23215        lsp::DiagnosticSeverity::WARNING => colors.warning,
23216        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23217        lsp::DiagnosticSeverity::HINT => colors.info,
23218        _ => colors.ignored,
23219    }
23220}
23221
23222pub fn styled_runs_for_code_label<'a>(
23223    label: &'a CodeLabel,
23224    syntax_theme: &'a theme::SyntaxTheme,
23225) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23226    let fade_out = HighlightStyle {
23227        fade_out: Some(0.35),
23228        ..Default::default()
23229    };
23230
23231    let mut prev_end = label.filter_range.end;
23232    label
23233        .runs
23234        .iter()
23235        .enumerate()
23236        .flat_map(move |(ix, (range, highlight_id))| {
23237            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23238                style
23239            } else {
23240                return Default::default();
23241            };
23242            let mut muted_style = style;
23243            muted_style.highlight(fade_out);
23244
23245            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23246            if range.start >= label.filter_range.end {
23247                if range.start > prev_end {
23248                    runs.push((prev_end..range.start, fade_out));
23249                }
23250                runs.push((range.clone(), muted_style));
23251            } else if range.end <= label.filter_range.end {
23252                runs.push((range.clone(), style));
23253            } else {
23254                runs.push((range.start..label.filter_range.end, style));
23255                runs.push((label.filter_range.end..range.end, muted_style));
23256            }
23257            prev_end = cmp::max(prev_end, range.end);
23258
23259            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23260                runs.push((prev_end..label.text.len(), fade_out));
23261            }
23262
23263            runs
23264        })
23265}
23266
23267pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23268    let mut prev_index = 0;
23269    let mut prev_codepoint: Option<char> = None;
23270    text.char_indices()
23271        .chain([(text.len(), '\0')])
23272        .filter_map(move |(index, codepoint)| {
23273            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23274            let is_boundary = index == text.len()
23275                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23276                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23277            if is_boundary {
23278                let chunk = &text[prev_index..index];
23279                prev_index = index;
23280                Some(chunk)
23281            } else {
23282                None
23283            }
23284        })
23285}
23286
23287pub trait RangeToAnchorExt: Sized {
23288    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23289
23290    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23291        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23292        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23293    }
23294}
23295
23296impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23297    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23298        let start_offset = self.start.to_offset(snapshot);
23299        let end_offset = self.end.to_offset(snapshot);
23300        if start_offset == end_offset {
23301            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23302        } else {
23303            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23304        }
23305    }
23306}
23307
23308pub trait RowExt {
23309    fn as_f32(&self) -> f32;
23310
23311    fn next_row(&self) -> Self;
23312
23313    fn previous_row(&self) -> Self;
23314
23315    fn minus(&self, other: Self) -> u32;
23316}
23317
23318impl RowExt for DisplayRow {
23319    fn as_f32(&self) -> f32 {
23320        self.0 as f32
23321    }
23322
23323    fn next_row(&self) -> Self {
23324        Self(self.0 + 1)
23325    }
23326
23327    fn previous_row(&self) -> Self {
23328        Self(self.0.saturating_sub(1))
23329    }
23330
23331    fn minus(&self, other: Self) -> u32 {
23332        self.0 - other.0
23333    }
23334}
23335
23336impl RowExt for MultiBufferRow {
23337    fn as_f32(&self) -> f32 {
23338        self.0 as f32
23339    }
23340
23341    fn next_row(&self) -> Self {
23342        Self(self.0 + 1)
23343    }
23344
23345    fn previous_row(&self) -> Self {
23346        Self(self.0.saturating_sub(1))
23347    }
23348
23349    fn minus(&self, other: Self) -> u32 {
23350        self.0 - other.0
23351    }
23352}
23353
23354trait RowRangeExt {
23355    type Row;
23356
23357    fn len(&self) -> usize;
23358
23359    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23360}
23361
23362impl RowRangeExt for Range<MultiBufferRow> {
23363    type Row = MultiBufferRow;
23364
23365    fn len(&self) -> usize {
23366        (self.end.0 - self.start.0) as usize
23367    }
23368
23369    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23370        (self.start.0..self.end.0).map(MultiBufferRow)
23371    }
23372}
23373
23374impl RowRangeExt for Range<DisplayRow> {
23375    type Row = DisplayRow;
23376
23377    fn len(&self) -> usize {
23378        (self.end.0 - self.start.0) as usize
23379    }
23380
23381    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23382        (self.start.0..self.end.0).map(DisplayRow)
23383    }
23384}
23385
23386/// If select range has more than one line, we
23387/// just point the cursor to range.start.
23388fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23389    if range.start.row == range.end.row {
23390        range
23391    } else {
23392        range.start..range.start
23393    }
23394}
23395pub struct KillRing(ClipboardItem);
23396impl Global for KillRing {}
23397
23398const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23399
23400enum BreakpointPromptEditAction {
23401    Log,
23402    Condition,
23403    HitCondition,
23404}
23405
23406struct BreakpointPromptEditor {
23407    pub(crate) prompt: Entity<Editor>,
23408    editor: WeakEntity<Editor>,
23409    breakpoint_anchor: Anchor,
23410    breakpoint: Breakpoint,
23411    edit_action: BreakpointPromptEditAction,
23412    block_ids: HashSet<CustomBlockId>,
23413    editor_margins: Arc<Mutex<EditorMargins>>,
23414    _subscriptions: Vec<Subscription>,
23415}
23416
23417impl BreakpointPromptEditor {
23418    const MAX_LINES: u8 = 4;
23419
23420    fn new(
23421        editor: WeakEntity<Editor>,
23422        breakpoint_anchor: Anchor,
23423        breakpoint: Breakpoint,
23424        edit_action: BreakpointPromptEditAction,
23425        window: &mut Window,
23426        cx: &mut Context<Self>,
23427    ) -> Self {
23428        let base_text = match edit_action {
23429            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23430            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23431            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23432        }
23433        .map(|msg| msg.to_string())
23434        .unwrap_or_default();
23435
23436        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23437        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23438
23439        let prompt = cx.new(|cx| {
23440            let mut prompt = Editor::new(
23441                EditorMode::AutoHeight {
23442                    min_lines: 1,
23443                    max_lines: Some(Self::MAX_LINES as usize),
23444                },
23445                buffer,
23446                None,
23447                window,
23448                cx,
23449            );
23450            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23451            prompt.set_show_cursor_when_unfocused(false, cx);
23452            prompt.set_placeholder_text(
23453                match edit_action {
23454                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23455                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23456                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23457                },
23458                cx,
23459            );
23460
23461            prompt
23462        });
23463
23464        Self {
23465            prompt,
23466            editor,
23467            breakpoint_anchor,
23468            breakpoint,
23469            edit_action,
23470            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23471            block_ids: Default::default(),
23472            _subscriptions: vec![],
23473        }
23474    }
23475
23476    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23477        self.block_ids.extend(block_ids)
23478    }
23479
23480    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23481        if let Some(editor) = self.editor.upgrade() {
23482            let message = self
23483                .prompt
23484                .read(cx)
23485                .buffer
23486                .read(cx)
23487                .as_singleton()
23488                .expect("A multi buffer in breakpoint prompt isn't possible")
23489                .read(cx)
23490                .as_rope()
23491                .to_string();
23492
23493            editor.update(cx, |editor, cx| {
23494                editor.edit_breakpoint_at_anchor(
23495                    self.breakpoint_anchor,
23496                    self.breakpoint.clone(),
23497                    match self.edit_action {
23498                        BreakpointPromptEditAction::Log => {
23499                            BreakpointEditAction::EditLogMessage(message.into())
23500                        }
23501                        BreakpointPromptEditAction::Condition => {
23502                            BreakpointEditAction::EditCondition(message.into())
23503                        }
23504                        BreakpointPromptEditAction::HitCondition => {
23505                            BreakpointEditAction::EditHitCondition(message.into())
23506                        }
23507                    },
23508                    cx,
23509                );
23510
23511                editor.remove_blocks(self.block_ids.clone(), None, cx);
23512                cx.focus_self(window);
23513            });
23514        }
23515    }
23516
23517    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23518        self.editor
23519            .update(cx, |editor, cx| {
23520                editor.remove_blocks(self.block_ids.clone(), None, cx);
23521                window.focus(&editor.focus_handle);
23522            })
23523            .log_err();
23524    }
23525
23526    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23527        let settings = ThemeSettings::get_global(cx);
23528        let text_style = TextStyle {
23529            color: if self.prompt.read(cx).read_only(cx) {
23530                cx.theme().colors().text_disabled
23531            } else {
23532                cx.theme().colors().text
23533            },
23534            font_family: settings.buffer_font.family.clone(),
23535            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23536            font_size: settings.buffer_font_size(cx).into(),
23537            font_weight: settings.buffer_font.weight,
23538            line_height: relative(settings.buffer_line_height.value()),
23539            ..Default::default()
23540        };
23541        EditorElement::new(
23542            &self.prompt,
23543            EditorStyle {
23544                background: cx.theme().colors().editor_background,
23545                local_player: cx.theme().players().local(),
23546                text: text_style,
23547                ..Default::default()
23548            },
23549        )
23550    }
23551}
23552
23553impl Render for BreakpointPromptEditor {
23554    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23555        let editor_margins = *self.editor_margins.lock();
23556        let gutter_dimensions = editor_margins.gutter;
23557        h_flex()
23558            .key_context("Editor")
23559            .bg(cx.theme().colors().editor_background)
23560            .border_y_1()
23561            .border_color(cx.theme().status().info_border)
23562            .size_full()
23563            .py(window.line_height() / 2.5)
23564            .on_action(cx.listener(Self::confirm))
23565            .on_action(cx.listener(Self::cancel))
23566            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23567            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23568    }
23569}
23570
23571impl Focusable for BreakpointPromptEditor {
23572    fn focus_handle(&self, cx: &App) -> FocusHandle {
23573        self.prompt.focus_handle(cx)
23574    }
23575}
23576
23577fn all_edits_insertions_or_deletions(
23578    edits: &Vec<(Range<Anchor>, String)>,
23579    snapshot: &MultiBufferSnapshot,
23580) -> bool {
23581    let mut all_insertions = true;
23582    let mut all_deletions = true;
23583
23584    for (range, new_text) in edits.iter() {
23585        let range_is_empty = range.to_offset(&snapshot).is_empty();
23586        let text_is_empty = new_text.is_empty();
23587
23588        if range_is_empty != text_is_empty {
23589            if range_is_empty {
23590                all_deletions = false;
23591            } else {
23592                all_insertions = false;
23593            }
23594        } else {
23595            return false;
23596        }
23597
23598        if !all_insertions && !all_deletions {
23599            return false;
23600        }
23601    }
23602    all_insertions || all_deletions
23603}
23604
23605struct MissingEditPredictionKeybindingTooltip;
23606
23607impl Render for MissingEditPredictionKeybindingTooltip {
23608    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23609        ui::tooltip_container(window, cx, |container, _, cx| {
23610            container
23611                .flex_shrink_0()
23612                .max_w_80()
23613                .min_h(rems_from_px(124.))
23614                .justify_between()
23615                .child(
23616                    v_flex()
23617                        .flex_1()
23618                        .text_ui_sm(cx)
23619                        .child(Label::new("Conflict with Accept Keybinding"))
23620                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23621                )
23622                .child(
23623                    h_flex()
23624                        .pb_1()
23625                        .gap_1()
23626                        .items_end()
23627                        .w_full()
23628                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23629                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23630                        }))
23631                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23632                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23633                        })),
23634                )
23635        })
23636    }
23637}
23638
23639#[derive(Debug, Clone, Copy, PartialEq)]
23640pub struct LineHighlight {
23641    pub background: Background,
23642    pub border: Option<gpui::Hsla>,
23643    pub include_gutter: bool,
23644    pub type_id: Option<TypeId>,
23645}
23646
23647struct LineManipulationResult {
23648    pub new_text: String,
23649    pub line_count_before: usize,
23650    pub line_count_after: usize,
23651}
23652
23653fn render_diff_hunk_controls(
23654    row: u32,
23655    status: &DiffHunkStatus,
23656    hunk_range: Range<Anchor>,
23657    is_created_file: bool,
23658    line_height: Pixels,
23659    editor: &Entity<Editor>,
23660    _window: &mut Window,
23661    cx: &mut App,
23662) -> AnyElement {
23663    h_flex()
23664        .h(line_height)
23665        .mr_1()
23666        .gap_1()
23667        .px_0p5()
23668        .pb_1()
23669        .border_x_1()
23670        .border_b_1()
23671        .border_color(cx.theme().colors().border_variant)
23672        .rounded_b_lg()
23673        .bg(cx.theme().colors().editor_background)
23674        .gap_1()
23675        .block_mouse_except_scroll()
23676        .shadow_md()
23677        .child(if status.has_secondary_hunk() {
23678            Button::new(("stage", row as u64), "Stage")
23679                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23680                .tooltip({
23681                    let focus_handle = editor.focus_handle(cx);
23682                    move |window, cx| {
23683                        Tooltip::for_action_in(
23684                            "Stage Hunk",
23685                            &::git::ToggleStaged,
23686                            &focus_handle,
23687                            window,
23688                            cx,
23689                        )
23690                    }
23691                })
23692                .on_click({
23693                    let editor = editor.clone();
23694                    move |_event, _window, cx| {
23695                        editor.update(cx, |editor, cx| {
23696                            editor.stage_or_unstage_diff_hunks(
23697                                true,
23698                                vec![hunk_range.start..hunk_range.start],
23699                                cx,
23700                            );
23701                        });
23702                    }
23703                })
23704        } else {
23705            Button::new(("unstage", row as u64), "Unstage")
23706                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23707                .tooltip({
23708                    let focus_handle = editor.focus_handle(cx);
23709                    move |window, cx| {
23710                        Tooltip::for_action_in(
23711                            "Unstage Hunk",
23712                            &::git::ToggleStaged,
23713                            &focus_handle,
23714                            window,
23715                            cx,
23716                        )
23717                    }
23718                })
23719                .on_click({
23720                    let editor = editor.clone();
23721                    move |_event, _window, cx| {
23722                        editor.update(cx, |editor, cx| {
23723                            editor.stage_or_unstage_diff_hunks(
23724                                false,
23725                                vec![hunk_range.start..hunk_range.start],
23726                                cx,
23727                            );
23728                        });
23729                    }
23730                })
23731        })
23732        .child(
23733            Button::new(("restore", row as u64), "Restore")
23734                .tooltip({
23735                    let focus_handle = editor.focus_handle(cx);
23736                    move |window, cx| {
23737                        Tooltip::for_action_in(
23738                            "Restore Hunk",
23739                            &::git::Restore,
23740                            &focus_handle,
23741                            window,
23742                            cx,
23743                        )
23744                    }
23745                })
23746                .on_click({
23747                    let editor = editor.clone();
23748                    move |_event, window, cx| {
23749                        editor.update(cx, |editor, cx| {
23750                            let snapshot = editor.snapshot(window, cx);
23751                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23752                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23753                        });
23754                    }
23755                })
23756                .disabled(is_created_file),
23757        )
23758        .when(
23759            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23760            |el| {
23761                el.child(
23762                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23763                        .shape(IconButtonShape::Square)
23764                        .icon_size(IconSize::Small)
23765                        // .disabled(!has_multiple_hunks)
23766                        .tooltip({
23767                            let focus_handle = editor.focus_handle(cx);
23768                            move |window, cx| {
23769                                Tooltip::for_action_in(
23770                                    "Next Hunk",
23771                                    &GoToHunk,
23772                                    &focus_handle,
23773                                    window,
23774                                    cx,
23775                                )
23776                            }
23777                        })
23778                        .on_click({
23779                            let editor = editor.clone();
23780                            move |_event, window, cx| {
23781                                editor.update(cx, |editor, cx| {
23782                                    let snapshot = editor.snapshot(window, cx);
23783                                    let position =
23784                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23785                                    editor.go_to_hunk_before_or_after_position(
23786                                        &snapshot,
23787                                        position,
23788                                        Direction::Next,
23789                                        window,
23790                                        cx,
23791                                    );
23792                                    editor.expand_selected_diff_hunks(cx);
23793                                });
23794                            }
23795                        }),
23796                )
23797                .child(
23798                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23799                        .shape(IconButtonShape::Square)
23800                        .icon_size(IconSize::Small)
23801                        // .disabled(!has_multiple_hunks)
23802                        .tooltip({
23803                            let focus_handle = editor.focus_handle(cx);
23804                            move |window, cx| {
23805                                Tooltip::for_action_in(
23806                                    "Previous Hunk",
23807                                    &GoToPreviousHunk,
23808                                    &focus_handle,
23809                                    window,
23810                                    cx,
23811                                )
23812                            }
23813                        })
23814                        .on_click({
23815                            let editor = editor.clone();
23816                            move |_event, window, cx| {
23817                                editor.update(cx, |editor, cx| {
23818                                    let snapshot = editor.snapshot(window, cx);
23819                                    let point =
23820                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23821                                    editor.go_to_hunk_before_or_after_position(
23822                                        &snapshot,
23823                                        point,
23824                                        Direction::Prev,
23825                                        window,
23826                                        cx,
23827                                    );
23828                                    editor.expand_selected_diff_hunks(cx);
23829                                });
23830                            }
23831                        }),
23832                )
23833            },
23834        )
23835        .into_any_element()
23836}