editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359            workspace.register_action(Editor::toggle_focus);
  360        },
  361    )
  362    .detach();
  363
  364    cx.on_action(move |_: &workspace::NewFile, cx| {
  365        let app_state = workspace::AppState::global(cx);
  366        if let Some(app_state) = app_state.upgrade() {
  367            workspace::open_new(
  368                Default::default(),
  369                app_state,
  370                cx,
  371                |workspace, window, cx| {
  372                    Editor::new_file(workspace, &Default::default(), window, cx)
  373                },
  374            )
  375            .detach();
  376        }
  377    });
  378    cx.on_action(move |_: &workspace::NewWindow, cx| {
  379        let app_state = workspace::AppState::global(cx);
  380        if let Some(app_state) = app_state.upgrade() {
  381            workspace::open_new(
  382                Default::default(),
  383                app_state,
  384                cx,
  385                |workspace, window, cx| {
  386                    cx.activate(true);
  387                    Editor::new_file(workspace, &Default::default(), window, cx)
  388                },
  389            )
  390            .detach();
  391        }
  392    });
  393}
  394
  395pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  396    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  397}
  398
  399pub trait DiagnosticRenderer {
  400    fn render_group(
  401        &self,
  402        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  403        buffer_id: BufferId,
  404        snapshot: EditorSnapshot,
  405        editor: WeakEntity<Editor>,
  406        cx: &mut App,
  407    ) -> Vec<BlockProperties<Anchor>>;
  408
  409    fn render_hover(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        range: Range<Point>,
  413        buffer_id: BufferId,
  414        cx: &mut App,
  415    ) -> Option<Entity<markdown::Markdown>>;
  416
  417    fn open_link(
  418        &self,
  419        editor: &mut Editor,
  420        link: SharedString,
  421        window: &mut Window,
  422        cx: &mut Context<Editor>,
  423    );
  424}
  425
  426pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  427
  428impl GlobalDiagnosticRenderer {
  429    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  430        cx.try_global::<Self>().map(|g| g.0.clone())
  431    }
  432}
  433
  434impl gpui::Global for GlobalDiagnosticRenderer {}
  435pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  436    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  437}
  438
  439pub struct SearchWithinRange;
  440
  441trait InvalidationRegion {
  442    fn ranges(&self) -> &[Range<Anchor>];
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum SelectPhase {
  447    Begin {
  448        position: DisplayPoint,
  449        add: bool,
  450        click_count: usize,
  451    },
  452    BeginColumnar {
  453        position: DisplayPoint,
  454        reset: bool,
  455        mode: ColumnarMode,
  456        goal_column: u32,
  457    },
  458    Extend {
  459        position: DisplayPoint,
  460        click_count: usize,
  461    },
  462    Update {
  463        position: DisplayPoint,
  464        goal_column: u32,
  465        scroll_delta: gpui::Point<f32>,
  466    },
  467    End,
  468}
  469
  470#[derive(Clone, Debug, PartialEq)]
  471pub enum ColumnarMode {
  472    FromMouse,
  473    FromSelection,
  474}
  475
  476#[derive(Clone, Debug)]
  477pub enum SelectMode {
  478    Character,
  479    Word(Range<Anchor>),
  480    Line(Range<Anchor>),
  481    All,
  482}
  483
  484#[derive(Clone, PartialEq, Eq, Debug)]
  485pub enum EditorMode {
  486    SingleLine,
  487    AutoHeight {
  488        min_lines: usize,
  489        max_lines: Option<usize>,
  490    },
  491    Full {
  492        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  493        scale_ui_elements_with_buffer_font_size: bool,
  494        /// When set to `true`, the editor will render a background for the active line.
  495        show_active_line_background: bool,
  496        /// When set to `true`, the editor's height will be determined by its content.
  497        sized_by_content: bool,
  498    },
  499    Minimap {
  500        parent: WeakEntity<Editor>,
  501    },
  502}
  503
  504impl EditorMode {
  505    pub fn full() -> Self {
  506        Self::Full {
  507            scale_ui_elements_with_buffer_font_size: true,
  508            show_active_line_background: true,
  509            sized_by_content: false,
  510        }
  511    }
  512
  513    #[inline]
  514    pub fn is_full(&self) -> bool {
  515        matches!(self, Self::Full { .. })
  516    }
  517
  518    #[inline]
  519    pub fn is_single_line(&self) -> bool {
  520        matches!(self, Self::SingleLine { .. })
  521    }
  522
  523    #[inline]
  524    fn is_minimap(&self) -> bool {
  525        matches!(self, Self::Minimap { .. })
  526    }
  527}
  528
  529#[derive(Copy, Clone, Debug)]
  530pub enum SoftWrap {
  531    /// Prefer not to wrap at all.
  532    ///
  533    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  534    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  535    GitDiff,
  536    /// Prefer a single line generally, unless an overly long line is encountered.
  537    None,
  538    /// Soft wrap lines that exceed the editor width.
  539    EditorWidth,
  540    /// Soft wrap lines at the preferred line length.
  541    Column(u32),
  542    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  543    Bounded(u32),
  544}
  545
  546#[derive(Clone)]
  547pub struct EditorStyle {
  548    pub background: Hsla,
  549    pub border: Hsla,
  550    pub local_player: PlayerColor,
  551    pub text: TextStyle,
  552    pub scrollbar_width: Pixels,
  553    pub syntax: Arc<SyntaxTheme>,
  554    pub status: StatusColors,
  555    pub inlay_hints_style: HighlightStyle,
  556    pub inline_completion_styles: InlineCompletionStyles,
  557    pub unnecessary_code_fade: f32,
  558    pub show_underlines: bool,
  559}
  560
  561impl Default for EditorStyle {
  562    fn default() -> Self {
  563        Self {
  564            background: Hsla::default(),
  565            border: Hsla::default(),
  566            local_player: PlayerColor::default(),
  567            text: TextStyle::default(),
  568            scrollbar_width: Pixels::default(),
  569            syntax: Default::default(),
  570            // HACK: Status colors don't have a real default.
  571            // We should look into removing the status colors from the editor
  572            // style and retrieve them directly from the theme.
  573            status: StatusColors::dark(),
  574            inlay_hints_style: HighlightStyle::default(),
  575            inline_completion_styles: InlineCompletionStyles {
  576                insertion: HighlightStyle::default(),
  577                whitespace: HighlightStyle::default(),
  578            },
  579            unnecessary_code_fade: Default::default(),
  580            show_underlines: true,
  581        }
  582    }
  583}
  584
  585pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  586    let show_background = language_settings::language_settings(None, None, cx)
  587        .inlay_hints
  588        .show_background;
  589
  590    HighlightStyle {
  591        color: Some(cx.theme().status().hint),
  592        background_color: show_background.then(|| cx.theme().status().hint_background),
  593        ..HighlightStyle::default()
  594    }
  595}
  596
  597pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  598    InlineCompletionStyles {
  599        insertion: HighlightStyle {
  600            color: Some(cx.theme().status().predictive),
  601            ..HighlightStyle::default()
  602        },
  603        whitespace: HighlightStyle {
  604            background_color: Some(cx.theme().status().created_background),
  605            ..HighlightStyle::default()
  606        },
  607    }
  608}
  609
  610type CompletionId = usize;
  611
  612pub(crate) enum EditDisplayMode {
  613    TabAccept,
  614    DiffPopover,
  615    Inline,
  616}
  617
  618enum InlineCompletion {
  619    Edit {
  620        edits: Vec<(Range<Anchor>, String)>,
  621        edit_preview: Option<EditPreview>,
  622        display_mode: EditDisplayMode,
  623        snapshot: BufferSnapshot,
  624    },
  625    Move {
  626        target: Anchor,
  627        snapshot: BufferSnapshot,
  628    },
  629}
  630
  631struct InlineCompletionState {
  632    inlay_ids: Vec<InlayId>,
  633    completion: InlineCompletion,
  634    completion_id: Option<SharedString>,
  635    invalidation_range: Range<Anchor>,
  636}
  637
  638enum EditPredictionSettings {
  639    Disabled,
  640    Enabled {
  641        show_in_menu: bool,
  642        preview_requires_modifier: bool,
  643    },
  644}
  645
  646enum InlineCompletionHighlight {}
  647
  648#[derive(Debug, Clone)]
  649struct InlineDiagnostic {
  650    message: SharedString,
  651    group_id: usize,
  652    is_primary: bool,
  653    start: Point,
  654    severity: lsp::DiagnosticSeverity,
  655}
  656
  657pub enum MenuInlineCompletionsPolicy {
  658    Never,
  659    ByProvider,
  660}
  661
  662pub enum EditPredictionPreview {
  663    /// Modifier is not pressed
  664    Inactive { released_too_fast: bool },
  665    /// Modifier pressed
  666    Active {
  667        since: Instant,
  668        previous_scroll_position: Option<ScrollAnchor>,
  669    },
  670}
  671
  672impl EditPredictionPreview {
  673    pub fn released_too_fast(&self) -> bool {
  674        match self {
  675            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  676            EditPredictionPreview::Active { .. } => false,
  677        }
  678    }
  679
  680    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  681        if let EditPredictionPreview::Active {
  682            previous_scroll_position,
  683            ..
  684        } = self
  685        {
  686            *previous_scroll_position = scroll_position;
  687        }
  688    }
  689}
  690
  691pub struct ContextMenuOptions {
  692    pub min_entries_visible: usize,
  693    pub max_entries_visible: usize,
  694    pub placement: Option<ContextMenuPlacement>,
  695}
  696
  697#[derive(Debug, Clone, PartialEq, Eq)]
  698pub enum ContextMenuPlacement {
  699    Above,
  700    Below,
  701}
  702
  703#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  704struct EditorActionId(usize);
  705
  706impl EditorActionId {
  707    pub fn post_inc(&mut self) -> Self {
  708        let answer = self.0;
  709
  710        *self = Self(answer + 1);
  711
  712        Self(answer)
  713    }
  714}
  715
  716// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  717// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  718
  719type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  720type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  721
  722#[derive(Default)]
  723struct ScrollbarMarkerState {
  724    scrollbar_size: Size<Pixels>,
  725    dirty: bool,
  726    markers: Arc<[PaintQuad]>,
  727    pending_refresh: Option<Task<Result<()>>>,
  728}
  729
  730impl ScrollbarMarkerState {
  731    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  732        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  733    }
  734}
  735
  736#[derive(Clone, Copy, PartialEq, Eq)]
  737pub enum MinimapVisibility {
  738    Disabled,
  739    Enabled {
  740        /// The configuration currently present in the users settings.
  741        setting_configuration: bool,
  742        /// Whether to override the currently set visibility from the users setting.
  743        toggle_override: bool,
  744    },
  745}
  746
  747impl MinimapVisibility {
  748    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  749        if mode.is_full() {
  750            Self::Enabled {
  751                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  752                toggle_override: false,
  753            }
  754        } else {
  755            Self::Disabled
  756        }
  757    }
  758
  759    fn hidden(&self) -> Self {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => Self::Enabled {
  765                setting_configuration,
  766                toggle_override: setting_configuration,
  767            },
  768            Self::Disabled => Self::Disabled,
  769        }
  770    }
  771
  772    fn disabled(&self) -> bool {
  773        match *self {
  774            Self::Disabled => true,
  775            _ => false,
  776        }
  777    }
  778
  779    fn settings_visibility(&self) -> bool {
  780        match *self {
  781            Self::Enabled {
  782                setting_configuration,
  783                ..
  784            } => setting_configuration,
  785            _ => false,
  786        }
  787    }
  788
  789    fn visible(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                toggle_override,
  794            } => setting_configuration ^ toggle_override,
  795            _ => false,
  796        }
  797    }
  798
  799    fn toggle_visibility(&self) -> Self {
  800        match *self {
  801            Self::Enabled {
  802                toggle_override,
  803                setting_configuration,
  804            } => Self::Enabled {
  805                setting_configuration,
  806                toggle_override: !toggle_override,
  807            },
  808            Self::Disabled => Self::Disabled,
  809        }
  810    }
  811}
  812
  813#[derive(Clone, Debug)]
  814struct RunnableTasks {
  815    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  816    offset: multi_buffer::Anchor,
  817    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  818    column: u32,
  819    // Values of all named captures, including those starting with '_'
  820    extra_variables: HashMap<String, String>,
  821    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  822    context_range: Range<BufferOffset>,
  823}
  824
  825impl RunnableTasks {
  826    fn resolve<'a>(
  827        &'a self,
  828        cx: &'a task::TaskContext,
  829    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  830        self.templates.iter().filter_map(|(kind, template)| {
  831            template
  832                .resolve_task(&kind.to_id_base(), cx)
  833                .map(|task| (kind.clone(), task))
  834        })
  835    }
  836}
  837
  838#[derive(Clone)]
  839pub struct ResolvedTasks {
  840    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  841    position: Anchor,
  842}
  843
  844#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  845struct BufferOffset(usize);
  846
  847// Addons allow storing per-editor state in other crates (e.g. Vim)
  848pub trait Addon: 'static {
  849    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  850
  851    fn render_buffer_header_controls(
  852        &self,
  853        _: &ExcerptInfo,
  854        _: &Window,
  855        _: &App,
  856    ) -> Option<AnyElement> {
  857        None
  858    }
  859
  860    fn to_any(&self) -> &dyn std::any::Any;
  861
  862    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  863        None
  864    }
  865}
  866
  867struct ChangeLocation {
  868    current: Option<Vec<Anchor>>,
  869    original: Vec<Anchor>,
  870}
  871impl ChangeLocation {
  872    fn locations(&self) -> &[Anchor] {
  873        self.current.as_ref().unwrap_or(&self.original)
  874    }
  875}
  876
  877/// A set of caret positions, registered when the editor was edited.
  878pub struct ChangeList {
  879    changes: Vec<ChangeLocation>,
  880    /// Currently "selected" change.
  881    position: Option<usize>,
  882}
  883
  884impl ChangeList {
  885    pub fn new() -> Self {
  886        Self {
  887            changes: Vec::new(),
  888            position: None,
  889        }
  890    }
  891
  892    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  893    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  894    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  895        if self.changes.is_empty() {
  896            return None;
  897        }
  898
  899        let prev = self.position.unwrap_or(self.changes.len());
  900        let next = if direction == Direction::Prev {
  901            prev.saturating_sub(count)
  902        } else {
  903            (prev + count).min(self.changes.len() - 1)
  904        };
  905        self.position = Some(next);
  906        self.changes.get(next).map(|change| change.locations())
  907    }
  908
  909    /// Adds a new change to the list, resetting the change list position.
  910    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  911        self.position.take();
  912        if let Some(last) = self.changes.last_mut()
  913            && group
  914        {
  915            last.current = Some(new_positions)
  916        } else {
  917            self.changes.push(ChangeLocation {
  918                original: new_positions,
  919                current: None,
  920            });
  921        }
  922    }
  923
  924    pub fn last(&self) -> Option<&[Anchor]> {
  925        self.changes.last().map(|change| change.locations())
  926    }
  927
  928    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  929        self.changes.last().map(|change| change.original.as_slice())
  930    }
  931
  932    pub fn invert_last_group(&mut self) {
  933        if let Some(last) = self.changes.last_mut() {
  934            if let Some(current) = last.current.as_mut() {
  935                mem::swap(&mut last.original, current);
  936            }
  937        }
  938    }
  939}
  940
  941#[derive(Clone)]
  942struct InlineBlamePopoverState {
  943    scroll_handle: ScrollHandle,
  944    commit_message: Option<ParsedCommitMessage>,
  945    markdown: Entity<Markdown>,
  946}
  947
  948struct InlineBlamePopover {
  949    position: gpui::Point<Pixels>,
  950    hide_task: Option<Task<()>>,
  951    popover_bounds: Option<Bounds<Pixels>>,
  952    popover_state: InlineBlamePopoverState,
  953    keyboard_grace: bool,
  954}
  955
  956enum SelectionDragState {
  957    /// State when no drag related activity is detected.
  958    None,
  959    /// State when the mouse is down on a selection that is about to be dragged.
  960    ReadyToDrag {
  961        selection: Selection<Anchor>,
  962        click_position: gpui::Point<Pixels>,
  963        mouse_down_time: Instant,
  964    },
  965    /// State when the mouse is dragging the selection in the editor.
  966    Dragging {
  967        selection: Selection<Anchor>,
  968        drop_cursor: Selection<Anchor>,
  969        hide_drop_cursor: bool,
  970    },
  971}
  972
  973enum ColumnarSelectionState {
  974    FromMouse {
  975        selection_tail: Anchor,
  976        display_point: Option<DisplayPoint>,
  977    },
  978    FromSelection {
  979        selection_tail: Anchor,
  980    },
  981}
  982
  983/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  984/// a breakpoint on them.
  985#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  986struct PhantomBreakpointIndicator {
  987    display_row: DisplayRow,
  988    /// There's a small debounce between hovering over the line and showing the indicator.
  989    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  990    is_active: bool,
  991    collides_with_existing_breakpoint: bool,
  992}
  993
  994/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  995///
  996/// See the [module level documentation](self) for more information.
  997pub struct Editor {
  998    focus_handle: FocusHandle,
  999    last_focused_descendant: Option<WeakFocusHandle>,
 1000    /// The text buffer being edited
 1001    buffer: Entity<MultiBuffer>,
 1002    /// Map of how text in the buffer should be displayed.
 1003    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1004    pub display_map: Entity<DisplayMap>,
 1005    pub selections: SelectionsCollection,
 1006    pub scroll_manager: ScrollManager,
 1007    /// When inline assist editors are linked, they all render cursors because
 1008    /// typing enters text into each of them, even the ones that aren't focused.
 1009    pub(crate) show_cursor_when_unfocused: bool,
 1010    columnar_selection_state: Option<ColumnarSelectionState>,
 1011    add_selections_state: Option<AddSelectionsState>,
 1012    select_next_state: Option<SelectNextState>,
 1013    select_prev_state: Option<SelectNextState>,
 1014    selection_history: SelectionHistory,
 1015    defer_selection_effects: bool,
 1016    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1017    autoclose_regions: Vec<AutocloseRegion>,
 1018    snippet_stack: InvalidationStack<SnippetState>,
 1019    select_syntax_node_history: SelectSyntaxNodeHistory,
 1020    ime_transaction: Option<TransactionId>,
 1021    pub diagnostics_max_severity: DiagnosticSeverity,
 1022    active_diagnostics: ActiveDiagnostic,
 1023    show_inline_diagnostics: bool,
 1024    inline_diagnostics_update: Task<()>,
 1025    inline_diagnostics_enabled: bool,
 1026    diagnostics_enabled: bool,
 1027    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1028    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1029    hard_wrap: Option<usize>,
 1030
 1031    // TODO: make this a access method
 1032    pub project: Option<Entity<Project>>,
 1033    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1034    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1035    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1036    blink_manager: Entity<BlinkManager>,
 1037    show_cursor_names: bool,
 1038    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1039    pub show_local_selections: bool,
 1040    mode: EditorMode,
 1041    show_breadcrumbs: bool,
 1042    show_gutter: bool,
 1043    show_scrollbars: ScrollbarAxes,
 1044    minimap_visibility: MinimapVisibility,
 1045    offset_content: bool,
 1046    disable_expand_excerpt_buttons: bool,
 1047    show_line_numbers: Option<bool>,
 1048    use_relative_line_numbers: Option<bool>,
 1049    show_git_diff_gutter: Option<bool>,
 1050    show_code_actions: Option<bool>,
 1051    show_runnables: Option<bool>,
 1052    show_breakpoints: Option<bool>,
 1053    show_wrap_guides: Option<bool>,
 1054    show_indent_guides: Option<bool>,
 1055    placeholder_text: Option<Arc<str>>,
 1056    highlight_order: usize,
 1057    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1058    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1059    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1060    scrollbar_marker_state: ScrollbarMarkerState,
 1061    active_indent_guides_state: ActiveIndentGuidesState,
 1062    nav_history: Option<ItemNavHistory>,
 1063    context_menu: RefCell<Option<CodeContextMenu>>,
 1064    context_menu_options: Option<ContextMenuOptions>,
 1065    mouse_context_menu: Option<MouseContextMenu>,
 1066    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1067    inline_blame_popover: Option<InlineBlamePopover>,
 1068    inline_blame_popover_show_task: Option<Task<()>>,
 1069    signature_help_state: SignatureHelpState,
 1070    auto_signature_help: Option<bool>,
 1071    find_all_references_task_sources: Vec<Anchor>,
 1072    next_completion_id: CompletionId,
 1073    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1074    code_actions_task: Option<Task<Result<()>>>,
 1075    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    document_highlights_task: Option<Task<()>>,
 1078    linked_editing_range_task: Option<Task<Option<()>>>,
 1079    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1080    pending_rename: Option<RenameState>,
 1081    searchable: bool,
 1082    cursor_shape: CursorShape,
 1083    current_line_highlight: Option<CurrentLineHighlight>,
 1084    collapse_matches: bool,
 1085    autoindent_mode: Option<AutoindentMode>,
 1086    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1087    input_enabled: bool,
 1088    use_modal_editing: bool,
 1089    read_only: bool,
 1090    leader_id: Option<CollaboratorId>,
 1091    remote_id: Option<ViewId>,
 1092    pub hover_state: HoverState,
 1093    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1094    gutter_hovered: bool,
 1095    hovered_link_state: Option<HoveredLinkState>,
 1096    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1097    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1098    active_inline_completion: Option<InlineCompletionState>,
 1099    /// Used to prevent flickering as the user types while the menu is open
 1100    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1101    edit_prediction_settings: EditPredictionSettings,
 1102    inline_completions_hidden_for_vim_mode: bool,
 1103    show_inline_completions_override: Option<bool>,
 1104    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1105    edit_prediction_preview: EditPredictionPreview,
 1106    edit_prediction_indent_conflict: bool,
 1107    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1108    inlay_hint_cache: InlayHintCache,
 1109    next_inlay_id: usize,
 1110    _subscriptions: Vec<Subscription>,
 1111    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1112    gutter_dimensions: GutterDimensions,
 1113    style: Option<EditorStyle>,
 1114    text_style_refinement: Option<TextStyleRefinement>,
 1115    next_editor_action_id: EditorActionId,
 1116    editor_actions: Rc<
 1117        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1118    >,
 1119    use_autoclose: bool,
 1120    use_auto_surround: bool,
 1121    auto_replace_emoji_shortcode: bool,
 1122    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1123    show_git_blame_gutter: bool,
 1124    show_git_blame_inline: bool,
 1125    show_git_blame_inline_delay_task: Option<Task<()>>,
 1126    git_blame_inline_enabled: bool,
 1127    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1128    serialize_dirty_buffers: bool,
 1129    show_selection_menu: Option<bool>,
 1130    blame: Option<Entity<GitBlame>>,
 1131    blame_subscription: Option<Subscription>,
 1132    custom_context_menu: Option<
 1133        Box<
 1134            dyn 'static
 1135                + Fn(
 1136                    &mut Self,
 1137                    DisplayPoint,
 1138                    &mut Window,
 1139                    &mut Context<Self>,
 1140                ) -> Option<Entity<ui::ContextMenu>>,
 1141        >,
 1142    >,
 1143    last_bounds: Option<Bounds<Pixels>>,
 1144    last_position_map: Option<Rc<PositionMap>>,
 1145    expect_bounds_change: Option<Bounds<Pixels>>,
 1146    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1147    tasks_update_task: Option<Task<()>>,
 1148    breakpoint_store: Option<Entity<BreakpointStore>>,
 1149    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1150    hovered_diff_hunk_row: Option<DisplayRow>,
 1151    pull_diagnostics_task: Task<()>,
 1152    in_project_search: bool,
 1153    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1154    breadcrumb_header: Option<String>,
 1155    focused_block: Option<FocusedBlock>,
 1156    next_scroll_position: NextScrollCursorCenterTopBottom,
 1157    addons: HashMap<TypeId, Box<dyn Addon>>,
 1158    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1159    load_diff_task: Option<Shared<Task<()>>>,
 1160    /// Whether we are temporarily displaying a diff other than git's
 1161    temporary_diff_override: bool,
 1162    selection_mark_mode: bool,
 1163    toggle_fold_multiple_buffers: Task<()>,
 1164    _scroll_cursor_center_top_bottom_task: Task<()>,
 1165    serialize_selections: Task<()>,
 1166    serialize_folds: Task<()>,
 1167    mouse_cursor_hidden: bool,
 1168    minimap: Option<Entity<Self>>,
 1169    hide_mouse_mode: HideMouseMode,
 1170    pub change_list: ChangeList,
 1171    inline_value_cache: InlineValueCache,
 1172    selection_drag_state: SelectionDragState,
 1173    next_color_inlay_id: usize,
 1174    colors: Option<LspColorData>,
 1175    folding_newlines: Task<()>,
 1176}
 1177
 1178#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1179enum NextScrollCursorCenterTopBottom {
 1180    #[default]
 1181    Center,
 1182    Top,
 1183    Bottom,
 1184}
 1185
 1186impl NextScrollCursorCenterTopBottom {
 1187    fn next(&self) -> Self {
 1188        match self {
 1189            Self::Center => Self::Top,
 1190            Self::Top => Self::Bottom,
 1191            Self::Bottom => Self::Center,
 1192        }
 1193    }
 1194}
 1195
 1196#[derive(Clone)]
 1197pub struct EditorSnapshot {
 1198    pub mode: EditorMode,
 1199    show_gutter: bool,
 1200    show_line_numbers: Option<bool>,
 1201    show_git_diff_gutter: Option<bool>,
 1202    show_code_actions: Option<bool>,
 1203    show_runnables: Option<bool>,
 1204    show_breakpoints: Option<bool>,
 1205    git_blame_gutter_max_author_length: Option<usize>,
 1206    pub display_snapshot: DisplaySnapshot,
 1207    pub placeholder_text: Option<Arc<str>>,
 1208    is_focused: bool,
 1209    scroll_anchor: ScrollAnchor,
 1210    ongoing_scroll: OngoingScroll,
 1211    current_line_highlight: CurrentLineHighlight,
 1212    gutter_hovered: bool,
 1213}
 1214
 1215#[derive(Default, Debug, Clone, Copy)]
 1216pub struct GutterDimensions {
 1217    pub left_padding: Pixels,
 1218    pub right_padding: Pixels,
 1219    pub width: Pixels,
 1220    pub margin: Pixels,
 1221    pub git_blame_entries_width: Option<Pixels>,
 1222}
 1223
 1224impl GutterDimensions {
 1225    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1226        Self {
 1227            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1228            ..Default::default()
 1229        }
 1230    }
 1231
 1232    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1233        -cx.text_system().descent(font_id, font_size)
 1234    }
 1235    /// The full width of the space taken up by the gutter.
 1236    pub fn full_width(&self) -> Pixels {
 1237        self.margin + self.width
 1238    }
 1239
 1240    /// The width of the space reserved for the fold indicators,
 1241    /// use alongside 'justify_end' and `gutter_width` to
 1242    /// right align content with the line numbers
 1243    pub fn fold_area_width(&self) -> Pixels {
 1244        self.margin + self.right_padding
 1245    }
 1246}
 1247
 1248struct CharacterDimensions {
 1249    em_width: Pixels,
 1250    em_advance: Pixels,
 1251    line_height: Pixels,
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct RemoteSelection {
 1256    pub replica_id: ReplicaId,
 1257    pub selection: Selection<Anchor>,
 1258    pub cursor_shape: CursorShape,
 1259    pub collaborator_id: CollaboratorId,
 1260    pub line_mode: bool,
 1261    pub user_name: Option<SharedString>,
 1262    pub color: PlayerColor,
 1263}
 1264
 1265#[derive(Clone, Debug)]
 1266struct SelectionHistoryEntry {
 1267    selections: Arc<[Selection<Anchor>]>,
 1268    select_next_state: Option<SelectNextState>,
 1269    select_prev_state: Option<SelectNextState>,
 1270    add_selections_state: Option<AddSelectionsState>,
 1271}
 1272
 1273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1274enum SelectionHistoryMode {
 1275    Normal,
 1276    Undoing,
 1277    Redoing,
 1278    Skipping,
 1279}
 1280
 1281#[derive(Clone, PartialEq, Eq, Hash)]
 1282struct HoveredCursor {
 1283    replica_id: u16,
 1284    selection_id: usize,
 1285}
 1286
 1287impl Default for SelectionHistoryMode {
 1288    fn default() -> Self {
 1289        Self::Normal
 1290    }
 1291}
 1292
 1293#[derive(Debug)]
 1294/// SelectionEffects controls the side-effects of updating the selection.
 1295///
 1296/// The default behaviour does "what you mostly want":
 1297/// - it pushes to the nav history if the cursor moved by >10 lines
 1298/// - it re-triggers completion requests
 1299/// - it scrolls to fit
 1300///
 1301/// You might want to modify these behaviours. For example when doing a "jump"
 1302/// like go to definition, we always want to add to nav history; but when scrolling
 1303/// in vim mode we never do.
 1304///
 1305/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1306/// move.
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .map_or(true, |e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredInlineCompletionProvider {
 1519    provider: Arc<dyn InlineCompletionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601#[derive(Debug, Clone)]
 1602enum InlayHintRefreshReason {
 1603    ModifiersChanged(bool),
 1604    Toggle(bool),
 1605    SettingsChange(InlayHintSettings),
 1606    NewLinesShown,
 1607    BufferEdited(HashSet<Arc<Language>>),
 1608    RefreshRequested,
 1609    ExcerptsRemoved(Vec<ExcerptId>),
 1610}
 1611
 1612impl InlayHintRefreshReason {
 1613    fn description(&self) -> &'static str {
 1614        match self {
 1615            Self::ModifiersChanged(_) => "modifiers changed",
 1616            Self::Toggle(_) => "toggle",
 1617            Self::SettingsChange(_) => "settings change",
 1618            Self::NewLinesShown => "new lines shown",
 1619            Self::BufferEdited(_) => "buffer edited",
 1620            Self::RefreshRequested => "refresh requested",
 1621            Self::ExcerptsRemoved(_) => "excerpts removed",
 1622        }
 1623    }
 1624}
 1625
 1626pub enum FormatTarget {
 1627    Buffers(HashSet<Entity<Buffer>>),
 1628    Ranges(Vec<Range<MultiBufferPoint>>),
 1629}
 1630
 1631pub(crate) struct FocusedBlock {
 1632    id: BlockId,
 1633    focus_handle: WeakFocusHandle,
 1634}
 1635
 1636#[derive(Clone)]
 1637enum JumpData {
 1638    MultiBufferRow {
 1639        row: MultiBufferRow,
 1640        line_offset_from_top: u32,
 1641    },
 1642    MultiBufferPoint {
 1643        excerpt_id: ExcerptId,
 1644        position: Point,
 1645        anchor: text::Anchor,
 1646        line_offset_from_top: u32,
 1647    },
 1648}
 1649
 1650pub enum MultibufferSelectionMode {
 1651    First,
 1652    All,
 1653}
 1654
 1655#[derive(Clone, Copy, Debug, Default)]
 1656pub struct RewrapOptions {
 1657    pub override_language_settings: bool,
 1658    pub preserve_existing_whitespace: bool,
 1659}
 1660
 1661impl Editor {
 1662    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1663        let buffer = cx.new(|cx| Buffer::local("", cx));
 1664        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1665        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1666    }
 1667
 1668    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::full(), buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn auto_height(
 1675        min_lines: usize,
 1676        max_lines: usize,
 1677        window: &mut Window,
 1678        cx: &mut Context<Self>,
 1679    ) -> Self {
 1680        let buffer = cx.new(|cx| Buffer::local("", cx));
 1681        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1682        Self::new(
 1683            EditorMode::AutoHeight {
 1684                min_lines,
 1685                max_lines: Some(max_lines),
 1686            },
 1687            buffer,
 1688            None,
 1689            window,
 1690            cx,
 1691        )
 1692    }
 1693
 1694    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1695    /// The editor grows as tall as needed to fit its content.
 1696    pub fn auto_height_unbounded(
 1697        min_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: None,
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    pub fn for_buffer(
 1716        buffer: Entity<Buffer>,
 1717        project: Option<Entity<Project>>,
 1718        window: &mut Window,
 1719        cx: &mut Context<Self>,
 1720    ) -> Self {
 1721        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn for_multibuffer(
 1726        buffer: Entity<MultiBuffer>,
 1727        project: Option<Entity<Project>>,
 1728        window: &mut Window,
 1729        cx: &mut Context<Self>,
 1730    ) -> Self {
 1731        Self::new(EditorMode::full(), buffer, project, window, cx)
 1732    }
 1733
 1734    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1735        let mut clone = Self::new(
 1736            self.mode.clone(),
 1737            self.buffer.clone(),
 1738            self.project.clone(),
 1739            window,
 1740            cx,
 1741        );
 1742        self.display_map.update(cx, |display_map, cx| {
 1743            let snapshot = display_map.snapshot(cx);
 1744            clone.display_map.update(cx, |display_map, cx| {
 1745                display_map.set_state(&snapshot, cx);
 1746            });
 1747        });
 1748        clone.folds_did_change(cx);
 1749        clone.selections.clone_state(&self.selections);
 1750        clone.scroll_manager.clone_state(&self.scroll_manager);
 1751        clone.searchable = self.searchable;
 1752        clone.read_only = self.read_only;
 1753        clone
 1754    }
 1755
 1756    pub fn new(
 1757        mode: EditorMode,
 1758        buffer: Entity<MultiBuffer>,
 1759        project: Option<Entity<Project>>,
 1760        window: &mut Window,
 1761        cx: &mut Context<Self>,
 1762    ) -> Self {
 1763        Editor::new_internal(mode, buffer, project, None, window, cx)
 1764    }
 1765
 1766    fn new_internal(
 1767        mode: EditorMode,
 1768        buffer: Entity<MultiBuffer>,
 1769        project: Option<Entity<Project>>,
 1770        display_map: Option<Entity<DisplayMap>>,
 1771        window: &mut Window,
 1772        cx: &mut Context<Self>,
 1773    ) -> Self {
 1774        debug_assert!(
 1775            display_map.is_none() || mode.is_minimap(),
 1776            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1777        );
 1778
 1779        let full_mode = mode.is_full();
 1780        let is_minimap = mode.is_minimap();
 1781        let diagnostics_max_severity = if full_mode {
 1782            EditorSettings::get_global(cx)
 1783                .diagnostics_max_severity
 1784                .unwrap_or(DiagnosticSeverity::Hint)
 1785        } else {
 1786            DiagnosticSeverity::Off
 1787        };
 1788        let style = window.text_style();
 1789        let font_size = style.font_size.to_pixels(window.rem_size());
 1790        let editor = cx.entity().downgrade();
 1791        let fold_placeholder = FoldPlaceholder {
 1792            constrain_width: true,
 1793            render: Arc::new(move |fold_id, fold_range, cx| {
 1794                let editor = editor.clone();
 1795                div()
 1796                    .id(fold_id)
 1797                    .bg(cx.theme().colors().ghost_element_background)
 1798                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1799                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1800                    .rounded_xs()
 1801                    .size_full()
 1802                    .cursor_pointer()
 1803                    .child("")
 1804                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1805                    .on_click(move |_, _window, cx| {
 1806                        editor
 1807                            .update(cx, |editor, cx| {
 1808                                editor.unfold_ranges(
 1809                                    &[fold_range.start..fold_range.end],
 1810                                    true,
 1811                                    false,
 1812                                    cx,
 1813                                );
 1814                                cx.stop_propagation();
 1815                            })
 1816                            .ok();
 1817                    })
 1818                    .into_any()
 1819            }),
 1820            merge_adjacent: true,
 1821            ..FoldPlaceholder::default()
 1822        };
 1823        let display_map = display_map.unwrap_or_else(|| {
 1824            cx.new(|cx| {
 1825                DisplayMap::new(
 1826                    buffer.clone(),
 1827                    style.font(),
 1828                    font_size,
 1829                    None,
 1830                    FILE_HEADER_HEIGHT,
 1831                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1832                    fold_placeholder,
 1833                    diagnostics_max_severity,
 1834                    cx,
 1835                )
 1836            })
 1837        });
 1838
 1839        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1840
 1841        let blink_manager = cx.new(|cx| {
 1842            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1843            if is_minimap {
 1844                blink_manager.disable(cx);
 1845            }
 1846            blink_manager
 1847        });
 1848
 1849        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1850            .then(|| language_settings::SoftWrap::None);
 1851
 1852        let mut project_subscriptions = Vec::new();
 1853        if full_mode {
 1854            if let Some(project) = project.as_ref() {
 1855                project_subscriptions.push(cx.subscribe_in(
 1856                    project,
 1857                    window,
 1858                    |editor, _, event, window, cx| match event {
 1859                        project::Event::RefreshCodeLens => {
 1860                            // we always query lens with actions, without storing them, always refreshing them
 1861                        }
 1862                        project::Event::RefreshInlayHints => {
 1863                            editor
 1864                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1865                        }
 1866                        project::Event::LanguageServerAdded(..)
 1867                        | project::Event::LanguageServerRemoved(..) => {
 1868                            if editor.tasks_update_task.is_none() {
 1869                                editor.tasks_update_task =
 1870                                    Some(editor.refresh_runnables(window, cx));
 1871                            }
 1872                            editor.update_lsp_data(true, None, window, cx);
 1873                        }
 1874                        project::Event::SnippetEdit(id, snippet_edits) => {
 1875                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1876                                let focus_handle = editor.focus_handle(cx);
 1877                                if focus_handle.is_focused(window) {
 1878                                    let snapshot = buffer.read(cx).snapshot();
 1879                                    for (range, snippet) in snippet_edits {
 1880                                        let editor_range =
 1881                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1882                                        editor
 1883                                            .insert_snippet(
 1884                                                &[editor_range],
 1885                                                snippet.clone(),
 1886                                                window,
 1887                                                cx,
 1888                                            )
 1889                                            .ok();
 1890                                    }
 1891                                }
 1892                            }
 1893                        }
 1894                        _ => {}
 1895                    },
 1896                ));
 1897                if let Some(task_inventory) = project
 1898                    .read(cx)
 1899                    .task_store()
 1900                    .read(cx)
 1901                    .task_inventory()
 1902                    .cloned()
 1903                {
 1904                    project_subscriptions.push(cx.observe_in(
 1905                        &task_inventory,
 1906                        window,
 1907                        |editor, _, window, cx| {
 1908                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1909                        },
 1910                    ));
 1911                };
 1912
 1913                project_subscriptions.push(cx.subscribe_in(
 1914                    &project.read(cx).breakpoint_store(),
 1915                    window,
 1916                    |editor, _, event, window, cx| match event {
 1917                        BreakpointStoreEvent::ClearDebugLines => {
 1918                            editor.clear_row_highlights::<ActiveDebugLine>();
 1919                            editor.refresh_inline_values(cx);
 1920                        }
 1921                        BreakpointStoreEvent::SetDebugLine => {
 1922                            if editor.go_to_active_debug_line(window, cx) {
 1923                                cx.stop_propagation();
 1924                            }
 1925
 1926                            editor.refresh_inline_values(cx);
 1927                        }
 1928                        _ => {}
 1929                    },
 1930                ));
 1931                let git_store = project.read(cx).git_store().clone();
 1932                let project = project.clone();
 1933                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1934                    match event {
 1935                        GitStoreEvent::RepositoryUpdated(
 1936                            _,
 1937                            RepositoryEvent::Updated {
 1938                                new_instance: true, ..
 1939                            },
 1940                            _,
 1941                        ) => {
 1942                            this.load_diff_task = Some(
 1943                                update_uncommitted_diff_for_buffer(
 1944                                    cx.entity(),
 1945                                    &project,
 1946                                    this.buffer.read(cx).all_buffers(),
 1947                                    this.buffer.clone(),
 1948                                    cx,
 1949                                )
 1950                                .shared(),
 1951                            );
 1952                        }
 1953                        _ => {}
 1954                    }
 1955                }));
 1956            }
 1957        }
 1958
 1959        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1960
 1961        let inlay_hint_settings =
 1962            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1963        let focus_handle = cx.focus_handle();
 1964        if !is_minimap {
 1965            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1966                .detach();
 1967            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1968                .detach();
 1969            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1970                .detach();
 1971            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1972                .detach();
 1973            cx.observe_pending_input(window, Self::observe_pending_input)
 1974                .detach();
 1975        }
 1976
 1977        let show_indent_guides = if matches!(
 1978            mode,
 1979            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1980        ) {
 1981            Some(false)
 1982        } else {
 1983            None
 1984        };
 1985
 1986        let breakpoint_store = match (&mode, project.as_ref()) {
 1987            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1988            _ => None,
 1989        };
 1990
 1991        let mut code_action_providers = Vec::new();
 1992        let mut load_uncommitted_diff = None;
 1993        if let Some(project) = project.clone() {
 1994            load_uncommitted_diff = Some(
 1995                update_uncommitted_diff_for_buffer(
 1996                    cx.entity(),
 1997                    &project,
 1998                    buffer.read(cx).all_buffers(),
 1999                    buffer.clone(),
 2000                    cx,
 2001                )
 2002                .shared(),
 2003            );
 2004            code_action_providers.push(Rc::new(project) as Rc<_>);
 2005        }
 2006
 2007        let mut editor = Self {
 2008            focus_handle,
 2009            show_cursor_when_unfocused: false,
 2010            last_focused_descendant: None,
 2011            buffer: buffer.clone(),
 2012            display_map: display_map.clone(),
 2013            selections,
 2014            scroll_manager: ScrollManager::new(cx),
 2015            columnar_selection_state: None,
 2016            add_selections_state: None,
 2017            select_next_state: None,
 2018            select_prev_state: None,
 2019            selection_history: SelectionHistory::default(),
 2020            defer_selection_effects: false,
 2021            deferred_selection_effects_state: None,
 2022            autoclose_regions: Vec::new(),
 2023            snippet_stack: InvalidationStack::default(),
 2024            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2025            ime_transaction: None,
 2026            active_diagnostics: ActiveDiagnostic::None,
 2027            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2028            inline_diagnostics_update: Task::ready(()),
 2029            inline_diagnostics: Vec::new(),
 2030            soft_wrap_mode_override,
 2031            diagnostics_max_severity,
 2032            hard_wrap: None,
 2033            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2035            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2036            project,
 2037            blink_manager: blink_manager.clone(),
 2038            show_local_selections: true,
 2039            show_scrollbars: ScrollbarAxes {
 2040                horizontal: full_mode,
 2041                vertical: full_mode,
 2042            },
 2043            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2044            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2045            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2046            show_gutter: full_mode,
 2047            show_line_numbers: (!full_mode).then_some(false),
 2048            use_relative_line_numbers: None,
 2049            disable_expand_excerpt_buttons: !full_mode,
 2050            show_git_diff_gutter: None,
 2051            show_code_actions: None,
 2052            show_runnables: None,
 2053            show_breakpoints: None,
 2054            show_wrap_guides: None,
 2055            show_indent_guides,
 2056            placeholder_text: None,
 2057            highlight_order: 0,
 2058            highlighted_rows: HashMap::default(),
 2059            background_highlights: TreeMap::default(),
 2060            gutter_highlights: TreeMap::default(),
 2061            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2062            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2063            nav_history: None,
 2064            context_menu: RefCell::new(None),
 2065            context_menu_options: None,
 2066            mouse_context_menu: None,
 2067            completion_tasks: Vec::new(),
 2068            inline_blame_popover: None,
 2069            inline_blame_popover_show_task: None,
 2070            signature_help_state: SignatureHelpState::default(),
 2071            auto_signature_help: None,
 2072            find_all_references_task_sources: Vec::new(),
 2073            next_completion_id: 0,
 2074            next_inlay_id: 0,
 2075            code_action_providers,
 2076            available_code_actions: None,
 2077            code_actions_task: None,
 2078            quick_selection_highlight_task: None,
 2079            debounced_selection_highlight_task: None,
 2080            document_highlights_task: None,
 2081            linked_editing_range_task: None,
 2082            pending_rename: None,
 2083            searchable: !is_minimap,
 2084            cursor_shape: EditorSettings::get_global(cx)
 2085                .cursor_shape
 2086                .unwrap_or_default(),
 2087            current_line_highlight: None,
 2088            autoindent_mode: Some(AutoindentMode::EachLine),
 2089            collapse_matches: false,
 2090            workspace: None,
 2091            input_enabled: !is_minimap,
 2092            use_modal_editing: full_mode,
 2093            read_only: is_minimap,
 2094            use_autoclose: true,
 2095            use_auto_surround: true,
 2096            auto_replace_emoji_shortcode: false,
 2097            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2098            leader_id: None,
 2099            remote_id: None,
 2100            hover_state: HoverState::default(),
 2101            pending_mouse_down: None,
 2102            hovered_link_state: None,
 2103            edit_prediction_provider: None,
 2104            active_inline_completion: None,
 2105            stale_inline_completion_in_menu: None,
 2106            edit_prediction_preview: EditPredictionPreview::Inactive {
 2107                released_too_fast: false,
 2108            },
 2109            inline_diagnostics_enabled: full_mode,
 2110            diagnostics_enabled: full_mode,
 2111            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2112            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2113            gutter_hovered: false,
 2114            pixel_position_of_newest_cursor: None,
 2115            last_bounds: None,
 2116            last_position_map: None,
 2117            expect_bounds_change: None,
 2118            gutter_dimensions: GutterDimensions::default(),
 2119            style: None,
 2120            show_cursor_names: false,
 2121            hovered_cursors: HashMap::default(),
 2122            next_editor_action_id: EditorActionId::default(),
 2123            editor_actions: Rc::default(),
 2124            inline_completions_hidden_for_vim_mode: false,
 2125            show_inline_completions_override: None,
 2126            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2127            edit_prediction_settings: EditPredictionSettings::Disabled,
 2128            edit_prediction_indent_conflict: false,
 2129            edit_prediction_requires_modifier_in_indent_conflict: true,
 2130            custom_context_menu: None,
 2131            show_git_blame_gutter: false,
 2132            show_git_blame_inline: false,
 2133            show_selection_menu: None,
 2134            show_git_blame_inline_delay_task: None,
 2135            git_blame_inline_enabled: full_mode
 2136                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2137            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2138            serialize_dirty_buffers: !is_minimap
 2139                && ProjectSettings::get_global(cx)
 2140                    .session
 2141                    .restore_unsaved_buffers,
 2142            blame: None,
 2143            blame_subscription: None,
 2144            tasks: BTreeMap::default(),
 2145
 2146            breakpoint_store,
 2147            gutter_breakpoint_indicator: (None, None),
 2148            hovered_diff_hunk_row: None,
 2149            _subscriptions: (!is_minimap)
 2150                .then(|| {
 2151                    vec![
 2152                        cx.observe(&buffer, Self::on_buffer_changed),
 2153                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2154                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2155                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2156                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2157                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2158                        cx.observe_window_activation(window, |editor, window, cx| {
 2159                            let active = window.is_window_active();
 2160                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2161                                if active {
 2162                                    blink_manager.enable(cx);
 2163                                } else {
 2164                                    blink_manager.disable(cx);
 2165                                }
 2166                            });
 2167                            if active {
 2168                                editor.show_mouse_cursor(cx);
 2169                            }
 2170                        }),
 2171                    ]
 2172                })
 2173                .unwrap_or_default(),
 2174            tasks_update_task: None,
 2175            pull_diagnostics_task: Task::ready(()),
 2176            colors: None,
 2177            next_color_inlay_id: 0,
 2178            linked_edit_ranges: Default::default(),
 2179            in_project_search: false,
 2180            previous_search_ranges: None,
 2181            breadcrumb_header: None,
 2182            focused_block: None,
 2183            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2184            addons: HashMap::default(),
 2185            registered_buffers: HashMap::default(),
 2186            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2187            selection_mark_mode: false,
 2188            toggle_fold_multiple_buffers: Task::ready(()),
 2189            serialize_selections: Task::ready(()),
 2190            serialize_folds: Task::ready(()),
 2191            text_style_refinement: None,
 2192            load_diff_task: load_uncommitted_diff,
 2193            temporary_diff_override: false,
 2194            mouse_cursor_hidden: false,
 2195            minimap: None,
 2196            hide_mouse_mode: EditorSettings::get_global(cx)
 2197                .hide_mouse
 2198                .unwrap_or_default(),
 2199            change_list: ChangeList::new(),
 2200            mode,
 2201            selection_drag_state: SelectionDragState::None,
 2202            folding_newlines: Task::ready(()),
 2203        };
 2204
 2205        if is_minimap {
 2206            return editor;
 2207        }
 2208
 2209        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2210            editor
 2211                ._subscriptions
 2212                .push(cx.observe(breakpoints, |_, _, cx| {
 2213                    cx.notify();
 2214                }));
 2215        }
 2216        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2217        editor._subscriptions.extend(project_subscriptions);
 2218
 2219        editor._subscriptions.push(cx.subscribe_in(
 2220            &cx.entity(),
 2221            window,
 2222            |editor, _, e: &EditorEvent, window, cx| match e {
 2223                EditorEvent::ScrollPositionChanged { local, .. } => {
 2224                    if *local {
 2225                        let new_anchor = editor.scroll_manager.anchor();
 2226                        let snapshot = editor.snapshot(window, cx);
 2227                        editor.update_restoration_data(cx, move |data| {
 2228                            data.scroll_position = (
 2229                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2230                                new_anchor.offset,
 2231                            );
 2232                        });
 2233                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2234                        editor.inline_blame_popover.take();
 2235                    }
 2236                }
 2237                EditorEvent::Edited { .. } => {
 2238                    if !vim_enabled(cx) {
 2239                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2240                        let pop_state = editor
 2241                            .change_list
 2242                            .last()
 2243                            .map(|previous| {
 2244                                previous.len() == selections.len()
 2245                                    && previous.iter().enumerate().all(|(ix, p)| {
 2246                                        p.to_display_point(&map).row()
 2247                                            == selections[ix].head().row()
 2248                                    })
 2249                            })
 2250                            .unwrap_or(false);
 2251                        let new_positions = selections
 2252                            .into_iter()
 2253                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2254                            .collect();
 2255                        editor
 2256                            .change_list
 2257                            .push_to_change_list(pop_state, new_positions);
 2258                    }
 2259                }
 2260                _ => (),
 2261            },
 2262        ));
 2263
 2264        if let Some(dap_store) = editor
 2265            .project
 2266            .as_ref()
 2267            .map(|project| project.read(cx).dap_store())
 2268        {
 2269            let weak_editor = cx.weak_entity();
 2270
 2271            editor
 2272                ._subscriptions
 2273                .push(
 2274                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2275                        let session_entity = cx.entity();
 2276                        weak_editor
 2277                            .update(cx, |editor, cx| {
 2278                                editor._subscriptions.push(
 2279                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2280                                );
 2281                            })
 2282                            .ok();
 2283                    }),
 2284                );
 2285
 2286            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2287                editor
 2288                    ._subscriptions
 2289                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2290            }
 2291        }
 2292
 2293        // skip adding the initial selection to selection history
 2294        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2295        editor.end_selection(window, cx);
 2296        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2297
 2298        editor.scroll_manager.show_scrollbars(window, cx);
 2299        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2300
 2301        if full_mode {
 2302            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2303            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2304
 2305            if editor.git_blame_inline_enabled {
 2306                editor.start_git_blame_inline(false, window, cx);
 2307            }
 2308
 2309            editor.go_to_active_debug_line(window, cx);
 2310
 2311            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2312                if let Some(project) = editor.project.as_ref() {
 2313                    let handle = project.update(cx, |project, cx| {
 2314                        project.register_buffer_with_language_servers(&buffer, cx)
 2315                    });
 2316                    editor
 2317                        .registered_buffers
 2318                        .insert(buffer.read(cx).remote_id(), handle);
 2319                }
 2320            }
 2321
 2322            editor.minimap =
 2323                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2324            editor.colors = Some(LspColorData::new(cx));
 2325            editor.update_lsp_data(false, None, window, cx);
 2326        }
 2327
 2328        if editor.mode.is_full() {
 2329            editor.report_editor_event("Editor Opened", None, cx);
 2330        }
 2331
 2332        editor
 2333    }
 2334
 2335    pub fn deploy_mouse_context_menu(
 2336        &mut self,
 2337        position: gpui::Point<Pixels>,
 2338        context_menu: Entity<ContextMenu>,
 2339        window: &mut Window,
 2340        cx: &mut Context<Self>,
 2341    ) {
 2342        self.mouse_context_menu = Some(MouseContextMenu::new(
 2343            self,
 2344            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2345            context_menu,
 2346            window,
 2347            cx,
 2348        ));
 2349    }
 2350
 2351    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2352        self.mouse_context_menu
 2353            .as_ref()
 2354            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2355    }
 2356
 2357    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2358        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2359    }
 2360
 2361    fn key_context_internal(
 2362        &self,
 2363        has_active_edit_prediction: bool,
 2364        window: &Window,
 2365        cx: &App,
 2366    ) -> KeyContext {
 2367        let mut key_context = KeyContext::new_with_defaults();
 2368        key_context.add("Editor");
 2369        let mode = match self.mode {
 2370            EditorMode::SingleLine { .. } => "single_line",
 2371            EditorMode::AutoHeight { .. } => "auto_height",
 2372            EditorMode::Minimap { .. } => "minimap",
 2373            EditorMode::Full { .. } => "full",
 2374        };
 2375
 2376        if EditorSettings::jupyter_enabled(cx) {
 2377            key_context.add("jupyter");
 2378        }
 2379
 2380        key_context.set("mode", mode);
 2381        if self.pending_rename.is_some() {
 2382            key_context.add("renaming");
 2383        }
 2384
 2385        match self.context_menu.borrow().as_ref() {
 2386            Some(CodeContextMenu::Completions(menu)) => {
 2387                if menu.visible() {
 2388                    key_context.add("menu");
 2389                    key_context.add("showing_completions");
 2390                }
 2391            }
 2392            Some(CodeContextMenu::CodeActions(menu)) => {
 2393                if menu.visible() {
 2394                    key_context.add("menu");
 2395                    key_context.add("showing_code_actions")
 2396                }
 2397            }
 2398            None => {}
 2399        }
 2400
 2401        if self.signature_help_state.has_multiple_signatures() {
 2402            key_context.add("showing_signature_help");
 2403        }
 2404
 2405        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2406        if !self.focus_handle(cx).contains_focused(window, cx)
 2407            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2408        {
 2409            for addon in self.addons.values() {
 2410                addon.extend_key_context(&mut key_context, cx)
 2411            }
 2412        }
 2413
 2414        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2415            if let Some(extension) = singleton_buffer
 2416                .read(cx)
 2417                .file()
 2418                .and_then(|file| file.path().extension()?.to_str())
 2419            {
 2420                key_context.set("extension", extension.to_string());
 2421            }
 2422        } else {
 2423            key_context.add("multibuffer");
 2424        }
 2425
 2426        if has_active_edit_prediction {
 2427            if self.edit_prediction_in_conflict() {
 2428                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2429            } else {
 2430                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2431                key_context.add("copilot_suggestion");
 2432            }
 2433        }
 2434
 2435        if self.selection_mark_mode {
 2436            key_context.add("selection_mode");
 2437        }
 2438
 2439        key_context
 2440    }
 2441
 2442    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2443        if self.mouse_cursor_hidden {
 2444            self.mouse_cursor_hidden = false;
 2445            cx.notify();
 2446        }
 2447    }
 2448
 2449    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2450        let hide_mouse_cursor = match origin {
 2451            HideMouseCursorOrigin::TypingAction => {
 2452                matches!(
 2453                    self.hide_mouse_mode,
 2454                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2455                )
 2456            }
 2457            HideMouseCursorOrigin::MovementAction => {
 2458                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2459            }
 2460        };
 2461        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2462            self.mouse_cursor_hidden = hide_mouse_cursor;
 2463            cx.notify();
 2464        }
 2465    }
 2466
 2467    pub fn edit_prediction_in_conflict(&self) -> bool {
 2468        if !self.show_edit_predictions_in_menu() {
 2469            return false;
 2470        }
 2471
 2472        let showing_completions = self
 2473            .context_menu
 2474            .borrow()
 2475            .as_ref()
 2476            .map_or(false, |context| {
 2477                matches!(context, CodeContextMenu::Completions(_))
 2478            });
 2479
 2480        showing_completions
 2481            || self.edit_prediction_requires_modifier()
 2482            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2483            // bindings to insert tab characters.
 2484            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2485    }
 2486
 2487    pub fn accept_edit_prediction_keybind(
 2488        &self,
 2489        accept_partial: bool,
 2490        window: &Window,
 2491        cx: &App,
 2492    ) -> AcceptEditPredictionBinding {
 2493        let key_context = self.key_context_internal(true, window, cx);
 2494        let in_conflict = self.edit_prediction_in_conflict();
 2495
 2496        let bindings = if accept_partial {
 2497            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2498        } else {
 2499            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2500        };
 2501
 2502        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2503        // just the first one.
 2504        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2505            !in_conflict
 2506                || binding
 2507                    .keystrokes()
 2508                    .first()
 2509                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2510        }))
 2511    }
 2512
 2513    pub fn new_file(
 2514        workspace: &mut Workspace,
 2515        _: &workspace::NewFile,
 2516        window: &mut Window,
 2517        cx: &mut Context<Workspace>,
 2518    ) {
 2519        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2520            "Failed to create buffer",
 2521            window,
 2522            cx,
 2523            |e, _, _| match e.error_code() {
 2524                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2525                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2526                e.error_tag("required").unwrap_or("the latest version")
 2527            )),
 2528                _ => None,
 2529            },
 2530        );
 2531    }
 2532
 2533    pub fn new_in_workspace(
 2534        workspace: &mut Workspace,
 2535        window: &mut Window,
 2536        cx: &mut Context<Workspace>,
 2537    ) -> Task<Result<Entity<Editor>>> {
 2538        let project = workspace.project().clone();
 2539        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2540
 2541        cx.spawn_in(window, async move |workspace, cx| {
 2542            let buffer = create.await?;
 2543            workspace.update_in(cx, |workspace, window, cx| {
 2544                let editor =
 2545                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2546                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2547                editor
 2548            })
 2549        })
 2550    }
 2551
 2552    fn new_file_vertical(
 2553        workspace: &mut Workspace,
 2554        _: &workspace::NewFileSplitVertical,
 2555        window: &mut Window,
 2556        cx: &mut Context<Workspace>,
 2557    ) {
 2558        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2559    }
 2560
 2561    fn new_file_horizontal(
 2562        workspace: &mut Workspace,
 2563        _: &workspace::NewFileSplitHorizontal,
 2564        window: &mut Window,
 2565        cx: &mut Context<Workspace>,
 2566    ) {
 2567        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2568    }
 2569
 2570    fn new_file_in_direction(
 2571        workspace: &mut Workspace,
 2572        direction: SplitDirection,
 2573        window: &mut Window,
 2574        cx: &mut Context<Workspace>,
 2575    ) {
 2576        let project = workspace.project().clone();
 2577        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2578
 2579        cx.spawn_in(window, async move |workspace, cx| {
 2580            let buffer = create.await?;
 2581            workspace.update_in(cx, move |workspace, window, cx| {
 2582                workspace.split_item(
 2583                    direction,
 2584                    Box::new(
 2585                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2586                    ),
 2587                    window,
 2588                    cx,
 2589                )
 2590            })?;
 2591            anyhow::Ok(())
 2592        })
 2593        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2594            match e.error_code() {
 2595                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2596                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2597                e.error_tag("required").unwrap_or("the latest version")
 2598            )),
 2599                _ => None,
 2600            }
 2601        });
 2602    }
 2603
 2604    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2605        self.leader_id
 2606    }
 2607
 2608    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2609        &self.buffer
 2610    }
 2611
 2612    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2613        self.workspace.as_ref()?.0.upgrade()
 2614    }
 2615
 2616    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2617        self.buffer().read(cx).title(cx)
 2618    }
 2619
 2620    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2621        let git_blame_gutter_max_author_length = self
 2622            .render_git_blame_gutter(cx)
 2623            .then(|| {
 2624                if let Some(blame) = self.blame.as_ref() {
 2625                    let max_author_length =
 2626                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2627                    Some(max_author_length)
 2628                } else {
 2629                    None
 2630                }
 2631            })
 2632            .flatten();
 2633
 2634        EditorSnapshot {
 2635            mode: self.mode.clone(),
 2636            show_gutter: self.show_gutter,
 2637            show_line_numbers: self.show_line_numbers,
 2638            show_git_diff_gutter: self.show_git_diff_gutter,
 2639            show_code_actions: self.show_code_actions,
 2640            show_runnables: self.show_runnables,
 2641            show_breakpoints: self.show_breakpoints,
 2642            git_blame_gutter_max_author_length,
 2643            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2644            scroll_anchor: self.scroll_manager.anchor(),
 2645            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2646            placeholder_text: self.placeholder_text.clone(),
 2647            is_focused: self.focus_handle.is_focused(window),
 2648            current_line_highlight: self
 2649                .current_line_highlight
 2650                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2651            gutter_hovered: self.gutter_hovered,
 2652        }
 2653    }
 2654
 2655    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2656        self.buffer.read(cx).language_at(point, cx)
 2657    }
 2658
 2659    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2660        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2661    }
 2662
 2663    pub fn active_excerpt(
 2664        &self,
 2665        cx: &App,
 2666    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2667        self.buffer
 2668            .read(cx)
 2669            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2670    }
 2671
 2672    pub fn mode(&self) -> &EditorMode {
 2673        &self.mode
 2674    }
 2675
 2676    pub fn set_mode(&mut self, mode: EditorMode) {
 2677        self.mode = mode;
 2678    }
 2679
 2680    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2681        self.collaboration_hub.as_deref()
 2682    }
 2683
 2684    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2685        self.collaboration_hub = Some(hub);
 2686    }
 2687
 2688    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2689        self.in_project_search = in_project_search;
 2690    }
 2691
 2692    pub fn set_custom_context_menu(
 2693        &mut self,
 2694        f: impl 'static
 2695        + Fn(
 2696            &mut Self,
 2697            DisplayPoint,
 2698            &mut Window,
 2699            &mut Context<Self>,
 2700        ) -> Option<Entity<ui::ContextMenu>>,
 2701    ) {
 2702        self.custom_context_menu = Some(Box::new(f))
 2703    }
 2704
 2705    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2706        self.completion_provider = provider;
 2707    }
 2708
 2709    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2710        self.semantics_provider.clone()
 2711    }
 2712
 2713    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2714        self.semantics_provider = provider;
 2715    }
 2716
 2717    pub fn set_edit_prediction_provider<T>(
 2718        &mut self,
 2719        provider: Option<Entity<T>>,
 2720        window: &mut Window,
 2721        cx: &mut Context<Self>,
 2722    ) where
 2723        T: EditPredictionProvider,
 2724    {
 2725        self.edit_prediction_provider =
 2726            provider.map(|provider| RegisteredInlineCompletionProvider {
 2727                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2728                    if this.focus_handle.is_focused(window) {
 2729                        this.update_visible_inline_completion(window, cx);
 2730                    }
 2731                }),
 2732                provider: Arc::new(provider),
 2733            });
 2734        self.update_edit_prediction_settings(cx);
 2735        self.refresh_inline_completion(false, false, window, cx);
 2736    }
 2737
 2738    pub fn placeholder_text(&self) -> Option<&str> {
 2739        self.placeholder_text.as_deref()
 2740    }
 2741
 2742    pub fn set_placeholder_text(
 2743        &mut self,
 2744        placeholder_text: impl Into<Arc<str>>,
 2745        cx: &mut Context<Self>,
 2746    ) {
 2747        let placeholder_text = Some(placeholder_text.into());
 2748        if self.placeholder_text != placeholder_text {
 2749            self.placeholder_text = placeholder_text;
 2750            cx.notify();
 2751        }
 2752    }
 2753
 2754    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2755        self.cursor_shape = cursor_shape;
 2756
 2757        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2758        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2759
 2760        cx.notify();
 2761    }
 2762
 2763    pub fn set_current_line_highlight(
 2764        &mut self,
 2765        current_line_highlight: Option<CurrentLineHighlight>,
 2766    ) {
 2767        self.current_line_highlight = current_line_highlight;
 2768    }
 2769
 2770    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2771        self.collapse_matches = collapse_matches;
 2772    }
 2773
 2774    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2775        let buffers = self.buffer.read(cx).all_buffers();
 2776        let Some(project) = self.project.as_ref() else {
 2777            return;
 2778        };
 2779        project.update(cx, |project, cx| {
 2780            for buffer in buffers {
 2781                self.registered_buffers
 2782                    .entry(buffer.read(cx).remote_id())
 2783                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2784            }
 2785        })
 2786    }
 2787
 2788    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2789        if self.collapse_matches {
 2790            return range.start..range.start;
 2791        }
 2792        range.clone()
 2793    }
 2794
 2795    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2796        if self.display_map.read(cx).clip_at_line_ends != clip {
 2797            self.display_map
 2798                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2799        }
 2800    }
 2801
 2802    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2803        self.input_enabled = input_enabled;
 2804    }
 2805
 2806    pub fn set_inline_completions_hidden_for_vim_mode(
 2807        &mut self,
 2808        hidden: bool,
 2809        window: &mut Window,
 2810        cx: &mut Context<Self>,
 2811    ) {
 2812        if hidden != self.inline_completions_hidden_for_vim_mode {
 2813            self.inline_completions_hidden_for_vim_mode = hidden;
 2814            if hidden {
 2815                self.update_visible_inline_completion(window, cx);
 2816            } else {
 2817                self.refresh_inline_completion(true, false, window, cx);
 2818            }
 2819        }
 2820    }
 2821
 2822    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2823        self.menu_inline_completions_policy = value;
 2824    }
 2825
 2826    pub fn set_autoindent(&mut self, autoindent: bool) {
 2827        if autoindent {
 2828            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2829        } else {
 2830            self.autoindent_mode = None;
 2831        }
 2832    }
 2833
 2834    pub fn read_only(&self, cx: &App) -> bool {
 2835        self.read_only || self.buffer.read(cx).read_only()
 2836    }
 2837
 2838    pub fn set_read_only(&mut self, read_only: bool) {
 2839        self.read_only = read_only;
 2840    }
 2841
 2842    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2843        self.use_autoclose = autoclose;
 2844    }
 2845
 2846    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2847        self.use_auto_surround = auto_surround;
 2848    }
 2849
 2850    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2851        self.auto_replace_emoji_shortcode = auto_replace;
 2852    }
 2853
 2854    pub fn toggle_edit_predictions(
 2855        &mut self,
 2856        _: &ToggleEditPrediction,
 2857        window: &mut Window,
 2858        cx: &mut Context<Self>,
 2859    ) {
 2860        if self.show_inline_completions_override.is_some() {
 2861            self.set_show_edit_predictions(None, window, cx);
 2862        } else {
 2863            let show_edit_predictions = !self.edit_predictions_enabled();
 2864            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2865        }
 2866    }
 2867
 2868    pub fn set_show_edit_predictions(
 2869        &mut self,
 2870        show_edit_predictions: Option<bool>,
 2871        window: &mut Window,
 2872        cx: &mut Context<Self>,
 2873    ) {
 2874        self.show_inline_completions_override = show_edit_predictions;
 2875        self.update_edit_prediction_settings(cx);
 2876
 2877        if let Some(false) = show_edit_predictions {
 2878            self.discard_inline_completion(false, cx);
 2879        } else {
 2880            self.refresh_inline_completion(false, true, window, cx);
 2881        }
 2882    }
 2883
 2884    fn inline_completions_disabled_in_scope(
 2885        &self,
 2886        buffer: &Entity<Buffer>,
 2887        buffer_position: language::Anchor,
 2888        cx: &App,
 2889    ) -> bool {
 2890        let snapshot = buffer.read(cx).snapshot();
 2891        let settings = snapshot.settings_at(buffer_position, cx);
 2892
 2893        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2894            return false;
 2895        };
 2896
 2897        scope.override_name().map_or(false, |scope_name| {
 2898            settings
 2899                .edit_predictions_disabled_in
 2900                .iter()
 2901                .any(|s| s == scope_name)
 2902        })
 2903    }
 2904
 2905    pub fn set_use_modal_editing(&mut self, to: bool) {
 2906        self.use_modal_editing = to;
 2907    }
 2908
 2909    pub fn use_modal_editing(&self) -> bool {
 2910        self.use_modal_editing
 2911    }
 2912
 2913    fn selections_did_change(
 2914        &mut self,
 2915        local: bool,
 2916        old_cursor_position: &Anchor,
 2917        effects: SelectionEffects,
 2918        window: &mut Window,
 2919        cx: &mut Context<Self>,
 2920    ) {
 2921        window.invalidate_character_coordinates();
 2922
 2923        // Copy selections to primary selection buffer
 2924        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2925        if local {
 2926            let selections = self.selections.all::<usize>(cx);
 2927            let buffer_handle = self.buffer.read(cx).read(cx);
 2928
 2929            let mut text = String::new();
 2930            for (index, selection) in selections.iter().enumerate() {
 2931                let text_for_selection = buffer_handle
 2932                    .text_for_range(selection.start..selection.end)
 2933                    .collect::<String>();
 2934
 2935                text.push_str(&text_for_selection);
 2936                if index != selections.len() - 1 {
 2937                    text.push('\n');
 2938                }
 2939            }
 2940
 2941            if !text.is_empty() {
 2942                cx.write_to_primary(ClipboardItem::new_string(text));
 2943            }
 2944        }
 2945
 2946        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2947            self.buffer.update(cx, |buffer, cx| {
 2948                buffer.set_active_selections(
 2949                    &self.selections.disjoint_anchors(),
 2950                    self.selections.line_mode,
 2951                    self.cursor_shape,
 2952                    cx,
 2953                )
 2954            });
 2955        }
 2956        let display_map = self
 2957            .display_map
 2958            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2959        let buffer = &display_map.buffer_snapshot;
 2960        if self.selections.count() == 1 {
 2961            self.add_selections_state = None;
 2962        }
 2963        self.select_next_state = None;
 2964        self.select_prev_state = None;
 2965        self.select_syntax_node_history.try_clear();
 2966        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2967        self.snippet_stack
 2968            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2969        self.take_rename(false, window, cx);
 2970
 2971        let newest_selection = self.selections.newest_anchor();
 2972        let new_cursor_position = newest_selection.head();
 2973        let selection_start = newest_selection.start;
 2974
 2975        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2976            self.push_to_nav_history(
 2977                *old_cursor_position,
 2978                Some(new_cursor_position.to_point(buffer)),
 2979                false,
 2980                effects.nav_history == Some(true),
 2981                cx,
 2982            );
 2983        }
 2984
 2985        if local {
 2986            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2987                if !self.registered_buffers.contains_key(&buffer_id) {
 2988                    if let Some(project) = self.project.as_ref() {
 2989                        project.update(cx, |project, cx| {
 2990                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2991                                return;
 2992                            };
 2993                            self.registered_buffers.insert(
 2994                                buffer_id,
 2995                                project.register_buffer_with_language_servers(&buffer, cx),
 2996                            );
 2997                        })
 2998                    }
 2999                }
 3000            }
 3001
 3002            let mut context_menu = self.context_menu.borrow_mut();
 3003            let completion_menu = match context_menu.as_ref() {
 3004                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3005                Some(CodeContextMenu::CodeActions(_)) => {
 3006                    *context_menu = None;
 3007                    None
 3008                }
 3009                None => None,
 3010            };
 3011            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3012            drop(context_menu);
 3013
 3014            if effects.completions {
 3015                if let Some(completion_position) = completion_position {
 3016                    let start_offset = selection_start.to_offset(buffer);
 3017                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3018                    let continue_showing = if position_matches {
 3019                        if self.snippet_stack.is_empty() {
 3020                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3021                        } else {
 3022                            // Snippet choices can be shown even when the cursor is in whitespace.
 3023                            // Dismissing the menu with actions like backspace is handled by
 3024                            // invalidation regions.
 3025                            true
 3026                        }
 3027                    } else {
 3028                        false
 3029                    };
 3030
 3031                    if continue_showing {
 3032                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3033                    } else {
 3034                        self.hide_context_menu(window, cx);
 3035                    }
 3036                }
 3037            }
 3038
 3039            hide_hover(self, cx);
 3040
 3041            if old_cursor_position.to_display_point(&display_map).row()
 3042                != new_cursor_position.to_display_point(&display_map).row()
 3043            {
 3044                self.available_code_actions.take();
 3045            }
 3046            self.refresh_code_actions(window, cx);
 3047            self.refresh_document_highlights(cx);
 3048            self.refresh_selected_text_highlights(false, window, cx);
 3049            refresh_matching_bracket_highlights(self, window, cx);
 3050            self.update_visible_inline_completion(window, cx);
 3051            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3052            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3053            self.inline_blame_popover.take();
 3054            if self.git_blame_inline_enabled {
 3055                self.start_inline_blame_timer(window, cx);
 3056            }
 3057        }
 3058
 3059        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3060        cx.emit(EditorEvent::SelectionsChanged { local });
 3061
 3062        let selections = &self.selections.disjoint;
 3063        if selections.len() == 1 {
 3064            cx.emit(SearchEvent::ActiveMatchChanged)
 3065        }
 3066        if local {
 3067            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3068                let inmemory_selections = selections
 3069                    .iter()
 3070                    .map(|s| {
 3071                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3072                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3073                    })
 3074                    .collect();
 3075                self.update_restoration_data(cx, |data| {
 3076                    data.selections = inmemory_selections;
 3077                });
 3078
 3079                if WorkspaceSettings::get(None, cx).restore_on_startup
 3080                    != RestoreOnStartupBehavior::None
 3081                {
 3082                    if let Some(workspace_id) =
 3083                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3084                    {
 3085                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3086                        let selections = selections.clone();
 3087                        let background_executor = cx.background_executor().clone();
 3088                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3089                        self.serialize_selections = cx.background_spawn(async move {
 3090                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3091                            let db_selections = selections
 3092                                .iter()
 3093                                .map(|selection| {
 3094                                    (
 3095                                        selection.start.to_offset(&snapshot),
 3096                                        selection.end.to_offset(&snapshot),
 3097                                    )
 3098                                })
 3099                                .collect();
 3100
 3101                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3102                                .await
 3103                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3104                                .log_err();
 3105                        });
 3106                    }
 3107                }
 3108            }
 3109        }
 3110
 3111        cx.notify();
 3112    }
 3113
 3114    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3115        use text::ToOffset as _;
 3116        use text::ToPoint as _;
 3117
 3118        if self.mode.is_minimap()
 3119            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3120        {
 3121            return;
 3122        }
 3123
 3124        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3125            return;
 3126        };
 3127
 3128        let snapshot = singleton.read(cx).snapshot();
 3129        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3130            let display_snapshot = display_map.snapshot(cx);
 3131
 3132            display_snapshot
 3133                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3134                .map(|fold| {
 3135                    fold.range.start.text_anchor.to_point(&snapshot)
 3136                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3137                })
 3138                .collect()
 3139        });
 3140        self.update_restoration_data(cx, |data| {
 3141            data.folds = inmemory_folds;
 3142        });
 3143
 3144        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3145            return;
 3146        };
 3147        let background_executor = cx.background_executor().clone();
 3148        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3149        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3150            display_map
 3151                .snapshot(cx)
 3152                .folds_in_range(0..snapshot.len())
 3153                .map(|fold| {
 3154                    (
 3155                        fold.range.start.text_anchor.to_offset(&snapshot),
 3156                        fold.range.end.text_anchor.to_offset(&snapshot),
 3157                    )
 3158                })
 3159                .collect()
 3160        });
 3161        self.serialize_folds = cx.background_spawn(async move {
 3162            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3163            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3164                .await
 3165                .with_context(|| {
 3166                    format!(
 3167                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3168                    )
 3169                })
 3170                .log_err();
 3171        });
 3172    }
 3173
 3174    pub fn sync_selections(
 3175        &mut self,
 3176        other: Entity<Editor>,
 3177        cx: &mut Context<Self>,
 3178    ) -> gpui::Subscription {
 3179        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3180        self.selections.change_with(cx, |selections| {
 3181            selections.select_anchors(other_selections);
 3182        });
 3183
 3184        let other_subscription =
 3185            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3186                EditorEvent::SelectionsChanged { local: true } => {
 3187                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3188                    if other_selections.is_empty() {
 3189                        return;
 3190                    }
 3191                    this.selections.change_with(cx, |selections| {
 3192                        selections.select_anchors(other_selections);
 3193                    });
 3194                }
 3195                _ => {}
 3196            });
 3197
 3198        let this_subscription =
 3199            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3200                EditorEvent::SelectionsChanged { local: true } => {
 3201                    let these_selections = this.selections.disjoint.to_vec();
 3202                    if these_selections.is_empty() {
 3203                        return;
 3204                    }
 3205                    other.update(cx, |other_editor, cx| {
 3206                        other_editor.selections.change_with(cx, |selections| {
 3207                            selections.select_anchors(these_selections);
 3208                        })
 3209                    });
 3210                }
 3211                _ => {}
 3212            });
 3213
 3214        Subscription::join(other_subscription, this_subscription)
 3215    }
 3216
 3217    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3218    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3219    /// effects of selection change occur at the end of the transaction.
 3220    pub fn change_selections<R>(
 3221        &mut self,
 3222        effects: SelectionEffects,
 3223        window: &mut Window,
 3224        cx: &mut Context<Self>,
 3225        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3226    ) -> R {
 3227        if let Some(state) = &mut self.deferred_selection_effects_state {
 3228            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3229            state.effects.completions = effects.completions;
 3230            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3231            let (changed, result) = self.selections.change_with(cx, change);
 3232            state.changed |= changed;
 3233            return result;
 3234        }
 3235        let mut state = DeferredSelectionEffectsState {
 3236            changed: false,
 3237            effects,
 3238            old_cursor_position: self.selections.newest_anchor().head(),
 3239            history_entry: SelectionHistoryEntry {
 3240                selections: self.selections.disjoint_anchors(),
 3241                select_next_state: self.select_next_state.clone(),
 3242                select_prev_state: self.select_prev_state.clone(),
 3243                add_selections_state: self.add_selections_state.clone(),
 3244            },
 3245        };
 3246        let (changed, result) = self.selections.change_with(cx, change);
 3247        state.changed = state.changed || changed;
 3248        if self.defer_selection_effects {
 3249            self.deferred_selection_effects_state = Some(state);
 3250        } else {
 3251            self.apply_selection_effects(state, window, cx);
 3252        }
 3253        result
 3254    }
 3255
 3256    /// Defers the effects of selection change, so that the effects of multiple calls to
 3257    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3258    /// to selection history and the state of popovers based on selection position aren't
 3259    /// erroneously updated.
 3260    pub fn with_selection_effects_deferred<R>(
 3261        &mut self,
 3262        window: &mut Window,
 3263        cx: &mut Context<Self>,
 3264        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3265    ) -> R {
 3266        let already_deferred = self.defer_selection_effects;
 3267        self.defer_selection_effects = true;
 3268        let result = update(self, window, cx);
 3269        if !already_deferred {
 3270            self.defer_selection_effects = false;
 3271            if let Some(state) = self.deferred_selection_effects_state.take() {
 3272                self.apply_selection_effects(state, window, cx);
 3273            }
 3274        }
 3275        result
 3276    }
 3277
 3278    fn apply_selection_effects(
 3279        &mut self,
 3280        state: DeferredSelectionEffectsState,
 3281        window: &mut Window,
 3282        cx: &mut Context<Self>,
 3283    ) {
 3284        if state.changed {
 3285            self.selection_history.push(state.history_entry);
 3286
 3287            if let Some(autoscroll) = state.effects.scroll {
 3288                self.request_autoscroll(autoscroll, cx);
 3289            }
 3290
 3291            let old_cursor_position = &state.old_cursor_position;
 3292
 3293            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3294
 3295            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3296                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3297            }
 3298        }
 3299    }
 3300
 3301    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3302    where
 3303        I: IntoIterator<Item = (Range<S>, T)>,
 3304        S: ToOffset,
 3305        T: Into<Arc<str>>,
 3306    {
 3307        if self.read_only(cx) {
 3308            return;
 3309        }
 3310
 3311        self.buffer
 3312            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3313    }
 3314
 3315    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3316    where
 3317        I: IntoIterator<Item = (Range<S>, T)>,
 3318        S: ToOffset,
 3319        T: Into<Arc<str>>,
 3320    {
 3321        if self.read_only(cx) {
 3322            return;
 3323        }
 3324
 3325        self.buffer.update(cx, |buffer, cx| {
 3326            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3327        });
 3328    }
 3329
 3330    pub fn edit_with_block_indent<I, S, T>(
 3331        &mut self,
 3332        edits: I,
 3333        original_indent_columns: Vec<Option<u32>>,
 3334        cx: &mut Context<Self>,
 3335    ) where
 3336        I: IntoIterator<Item = (Range<S>, T)>,
 3337        S: ToOffset,
 3338        T: Into<Arc<str>>,
 3339    {
 3340        if self.read_only(cx) {
 3341            return;
 3342        }
 3343
 3344        self.buffer.update(cx, |buffer, cx| {
 3345            buffer.edit(
 3346                edits,
 3347                Some(AutoindentMode::Block {
 3348                    original_indent_columns,
 3349                }),
 3350                cx,
 3351            )
 3352        });
 3353    }
 3354
 3355    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3356        self.hide_context_menu(window, cx);
 3357
 3358        match phase {
 3359            SelectPhase::Begin {
 3360                position,
 3361                add,
 3362                click_count,
 3363            } => self.begin_selection(position, add, click_count, window, cx),
 3364            SelectPhase::BeginColumnar {
 3365                position,
 3366                goal_column,
 3367                reset,
 3368                mode,
 3369            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3370            SelectPhase::Extend {
 3371                position,
 3372                click_count,
 3373            } => self.extend_selection(position, click_count, window, cx),
 3374            SelectPhase::Update {
 3375                position,
 3376                goal_column,
 3377                scroll_delta,
 3378            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3379            SelectPhase::End => self.end_selection(window, cx),
 3380        }
 3381    }
 3382
 3383    fn extend_selection(
 3384        &mut self,
 3385        position: DisplayPoint,
 3386        click_count: usize,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3391        let tail = self.selections.newest::<usize>(cx).tail();
 3392        self.begin_selection(position, false, click_count, window, cx);
 3393
 3394        let position = position.to_offset(&display_map, Bias::Left);
 3395        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3396
 3397        let mut pending_selection = self
 3398            .selections
 3399            .pending_anchor()
 3400            .expect("extend_selection not called with pending selection");
 3401        if position >= tail {
 3402            pending_selection.start = tail_anchor;
 3403        } else {
 3404            pending_selection.end = tail_anchor;
 3405            pending_selection.reversed = true;
 3406        }
 3407
 3408        let mut pending_mode = self.selections.pending_mode().unwrap();
 3409        match &mut pending_mode {
 3410            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3411            _ => {}
 3412        }
 3413
 3414        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3415            SelectionEffects::scroll(Autoscroll::fit())
 3416        } else {
 3417            SelectionEffects::no_scroll()
 3418        };
 3419
 3420        self.change_selections(effects, window, cx, |s| {
 3421            s.set_pending(pending_selection, pending_mode)
 3422        });
 3423    }
 3424
 3425    fn begin_selection(
 3426        &mut self,
 3427        position: DisplayPoint,
 3428        add: bool,
 3429        click_count: usize,
 3430        window: &mut Window,
 3431        cx: &mut Context<Self>,
 3432    ) {
 3433        if !self.focus_handle.is_focused(window) {
 3434            self.last_focused_descendant = None;
 3435            window.focus(&self.focus_handle);
 3436        }
 3437
 3438        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3439        let buffer = &display_map.buffer_snapshot;
 3440        let position = display_map.clip_point(position, Bias::Left);
 3441
 3442        let start;
 3443        let end;
 3444        let mode;
 3445        let mut auto_scroll;
 3446        match click_count {
 3447            1 => {
 3448                start = buffer.anchor_before(position.to_point(&display_map));
 3449                end = start;
 3450                mode = SelectMode::Character;
 3451                auto_scroll = true;
 3452            }
 3453            2 => {
 3454                let position = display_map
 3455                    .clip_point(position, Bias::Left)
 3456                    .to_offset(&display_map, Bias::Left);
 3457                let (range, _) = buffer.surrounding_word(position, false);
 3458                start = buffer.anchor_before(range.start);
 3459                end = buffer.anchor_before(range.end);
 3460                mode = SelectMode::Word(start..end);
 3461                auto_scroll = true;
 3462            }
 3463            3 => {
 3464                let position = display_map
 3465                    .clip_point(position, Bias::Left)
 3466                    .to_point(&display_map);
 3467                let line_start = display_map.prev_line_boundary(position).0;
 3468                let next_line_start = buffer.clip_point(
 3469                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3470                    Bias::Left,
 3471                );
 3472                start = buffer.anchor_before(line_start);
 3473                end = buffer.anchor_before(next_line_start);
 3474                mode = SelectMode::Line(start..end);
 3475                auto_scroll = true;
 3476            }
 3477            _ => {
 3478                start = buffer.anchor_before(0);
 3479                end = buffer.anchor_before(buffer.len());
 3480                mode = SelectMode::All;
 3481                auto_scroll = false;
 3482            }
 3483        }
 3484        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3485
 3486        let point_to_delete: Option<usize> = {
 3487            let selected_points: Vec<Selection<Point>> =
 3488                self.selections.disjoint_in_range(start..end, cx);
 3489
 3490            if !add || click_count > 1 {
 3491                None
 3492            } else if !selected_points.is_empty() {
 3493                Some(selected_points[0].id)
 3494            } else {
 3495                let clicked_point_already_selected =
 3496                    self.selections.disjoint.iter().find(|selection| {
 3497                        selection.start.to_point(buffer) == start.to_point(buffer)
 3498                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3499                    });
 3500
 3501                clicked_point_already_selected.map(|selection| selection.id)
 3502            }
 3503        };
 3504
 3505        let selections_count = self.selections.count();
 3506        let effects = if auto_scroll {
 3507            SelectionEffects::default()
 3508        } else {
 3509            SelectionEffects::no_scroll()
 3510        };
 3511
 3512        self.change_selections(effects, window, cx, |s| {
 3513            if let Some(point_to_delete) = point_to_delete {
 3514                s.delete(point_to_delete);
 3515
 3516                if selections_count == 1 {
 3517                    s.set_pending_anchor_range(start..end, mode);
 3518                }
 3519            } else {
 3520                if !add {
 3521                    s.clear_disjoint();
 3522                }
 3523
 3524                s.set_pending_anchor_range(start..end, mode);
 3525            }
 3526        });
 3527    }
 3528
 3529    fn begin_columnar_selection(
 3530        &mut self,
 3531        position: DisplayPoint,
 3532        goal_column: u32,
 3533        reset: bool,
 3534        mode: ColumnarMode,
 3535        window: &mut Window,
 3536        cx: &mut Context<Self>,
 3537    ) {
 3538        if !self.focus_handle.is_focused(window) {
 3539            self.last_focused_descendant = None;
 3540            window.focus(&self.focus_handle);
 3541        }
 3542
 3543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3544
 3545        if reset {
 3546            let pointer_position = display_map
 3547                .buffer_snapshot
 3548                .anchor_before(position.to_point(&display_map));
 3549
 3550            self.change_selections(
 3551                SelectionEffects::scroll(Autoscroll::newest()),
 3552                window,
 3553                cx,
 3554                |s| {
 3555                    s.clear_disjoint();
 3556                    s.set_pending_anchor_range(
 3557                        pointer_position..pointer_position,
 3558                        SelectMode::Character,
 3559                    );
 3560                },
 3561            );
 3562        };
 3563
 3564        let tail = self.selections.newest::<Point>(cx).tail();
 3565        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3566        self.columnar_selection_state = match mode {
 3567            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3568                selection_tail: selection_anchor,
 3569                display_point: if reset {
 3570                    if position.column() != goal_column {
 3571                        Some(DisplayPoint::new(position.row(), goal_column))
 3572                    } else {
 3573                        None
 3574                    }
 3575                } else {
 3576                    None
 3577                },
 3578            }),
 3579            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3580                selection_tail: selection_anchor,
 3581            }),
 3582        };
 3583
 3584        if !reset {
 3585            self.select_columns(position, goal_column, &display_map, window, cx);
 3586        }
 3587    }
 3588
 3589    fn update_selection(
 3590        &mut self,
 3591        position: DisplayPoint,
 3592        goal_column: u32,
 3593        scroll_delta: gpui::Point<f32>,
 3594        window: &mut Window,
 3595        cx: &mut Context<Self>,
 3596    ) {
 3597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3598
 3599        if self.columnar_selection_state.is_some() {
 3600            self.select_columns(position, goal_column, &display_map, window, cx);
 3601        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3602            let buffer = &display_map.buffer_snapshot;
 3603            let head;
 3604            let tail;
 3605            let mode = self.selections.pending_mode().unwrap();
 3606            match &mode {
 3607                SelectMode::Character => {
 3608                    head = position.to_point(&display_map);
 3609                    tail = pending.tail().to_point(buffer);
 3610                }
 3611                SelectMode::Word(original_range) => {
 3612                    let offset = display_map
 3613                        .clip_point(position, Bias::Left)
 3614                        .to_offset(&display_map, Bias::Left);
 3615                    let original_range = original_range.to_offset(buffer);
 3616
 3617                    let head_offset = if buffer.is_inside_word(offset, false)
 3618                        || original_range.contains(&offset)
 3619                    {
 3620                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3621                        if word_range.start < original_range.start {
 3622                            word_range.start
 3623                        } else {
 3624                            word_range.end
 3625                        }
 3626                    } else {
 3627                        offset
 3628                    };
 3629
 3630                    head = head_offset.to_point(buffer);
 3631                    if head_offset <= original_range.start {
 3632                        tail = original_range.end.to_point(buffer);
 3633                    } else {
 3634                        tail = original_range.start.to_point(buffer);
 3635                    }
 3636                }
 3637                SelectMode::Line(original_range) => {
 3638                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3639
 3640                    let position = display_map
 3641                        .clip_point(position, Bias::Left)
 3642                        .to_point(&display_map);
 3643                    let line_start = display_map.prev_line_boundary(position).0;
 3644                    let next_line_start = buffer.clip_point(
 3645                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3646                        Bias::Left,
 3647                    );
 3648
 3649                    if line_start < original_range.start {
 3650                        head = line_start
 3651                    } else {
 3652                        head = next_line_start
 3653                    }
 3654
 3655                    if head <= original_range.start {
 3656                        tail = original_range.end;
 3657                    } else {
 3658                        tail = original_range.start;
 3659                    }
 3660                }
 3661                SelectMode::All => {
 3662                    return;
 3663                }
 3664            };
 3665
 3666            if head < tail {
 3667                pending.start = buffer.anchor_before(head);
 3668                pending.end = buffer.anchor_before(tail);
 3669                pending.reversed = true;
 3670            } else {
 3671                pending.start = buffer.anchor_before(tail);
 3672                pending.end = buffer.anchor_before(head);
 3673                pending.reversed = false;
 3674            }
 3675
 3676            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3677                s.set_pending(pending, mode);
 3678            });
 3679        } else {
 3680            log::error!("update_selection dispatched with no pending selection");
 3681            return;
 3682        }
 3683
 3684        self.apply_scroll_delta(scroll_delta, window, cx);
 3685        cx.notify();
 3686    }
 3687
 3688    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3689        self.columnar_selection_state.take();
 3690        if self.selections.pending_anchor().is_some() {
 3691            let selections = self.selections.all::<usize>(cx);
 3692            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3693                s.select(selections);
 3694                s.clear_pending();
 3695            });
 3696        }
 3697    }
 3698
 3699    fn select_columns(
 3700        &mut self,
 3701        head: DisplayPoint,
 3702        goal_column: u32,
 3703        display_map: &DisplaySnapshot,
 3704        window: &mut Window,
 3705        cx: &mut Context<Self>,
 3706    ) {
 3707        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3708            return;
 3709        };
 3710
 3711        let tail = match columnar_state {
 3712            ColumnarSelectionState::FromMouse {
 3713                selection_tail,
 3714                display_point,
 3715            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3716            ColumnarSelectionState::FromSelection { selection_tail } => {
 3717                selection_tail.to_display_point(&display_map)
 3718            }
 3719        };
 3720
 3721        let start_row = cmp::min(tail.row(), head.row());
 3722        let end_row = cmp::max(tail.row(), head.row());
 3723        let start_column = cmp::min(tail.column(), goal_column);
 3724        let end_column = cmp::max(tail.column(), goal_column);
 3725        let reversed = start_column < tail.column();
 3726
 3727        let selection_ranges = (start_row.0..=end_row.0)
 3728            .map(DisplayRow)
 3729            .filter_map(|row| {
 3730                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3731                    || start_column <= display_map.line_len(row))
 3732                    && !display_map.is_block_line(row)
 3733                {
 3734                    let start = display_map
 3735                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3736                        .to_point(display_map);
 3737                    let end = display_map
 3738                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3739                        .to_point(display_map);
 3740                    if reversed {
 3741                        Some(end..start)
 3742                    } else {
 3743                        Some(start..end)
 3744                    }
 3745                } else {
 3746                    None
 3747                }
 3748            })
 3749            .collect::<Vec<_>>();
 3750
 3751        let ranges = match columnar_state {
 3752            ColumnarSelectionState::FromMouse { .. } => {
 3753                let mut non_empty_ranges = selection_ranges
 3754                    .iter()
 3755                    .filter(|selection_range| selection_range.start != selection_range.end)
 3756                    .peekable();
 3757                if non_empty_ranges.peek().is_some() {
 3758                    non_empty_ranges.cloned().collect()
 3759                } else {
 3760                    selection_ranges
 3761                }
 3762            }
 3763            _ => selection_ranges,
 3764        };
 3765
 3766        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3767            s.select_ranges(ranges);
 3768        });
 3769        cx.notify();
 3770    }
 3771
 3772    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3773        self.selections
 3774            .all_adjusted(cx)
 3775            .iter()
 3776            .any(|selection| !selection.is_empty())
 3777    }
 3778
 3779    pub fn has_pending_nonempty_selection(&self) -> bool {
 3780        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3781            Some(Selection { start, end, .. }) => start != end,
 3782            None => false,
 3783        };
 3784
 3785        pending_nonempty_selection
 3786            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3787    }
 3788
 3789    pub fn has_pending_selection(&self) -> bool {
 3790        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3791    }
 3792
 3793    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3794        self.selection_mark_mode = false;
 3795        self.selection_drag_state = SelectionDragState::None;
 3796
 3797        if self.clear_expanded_diff_hunks(cx) {
 3798            cx.notify();
 3799            return;
 3800        }
 3801        if self.dismiss_menus_and_popups(true, window, cx) {
 3802            return;
 3803        }
 3804
 3805        if self.mode.is_full()
 3806            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3807        {
 3808            return;
 3809        }
 3810
 3811        cx.propagate();
 3812    }
 3813
 3814    pub fn dismiss_menus_and_popups(
 3815        &mut self,
 3816        is_user_requested: bool,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819    ) -> bool {
 3820        if self.take_rename(false, window, cx).is_some() {
 3821            return true;
 3822        }
 3823
 3824        if hide_hover(self, cx) {
 3825            return true;
 3826        }
 3827
 3828        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3829            return true;
 3830        }
 3831
 3832        if self.hide_context_menu(window, cx).is_some() {
 3833            return true;
 3834        }
 3835
 3836        if self.mouse_context_menu.take().is_some() {
 3837            return true;
 3838        }
 3839
 3840        if is_user_requested && self.discard_inline_completion(true, cx) {
 3841            return true;
 3842        }
 3843
 3844        if self.snippet_stack.pop().is_some() {
 3845            return true;
 3846        }
 3847
 3848        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3849            self.dismiss_diagnostics(cx);
 3850            return true;
 3851        }
 3852
 3853        false
 3854    }
 3855
 3856    fn linked_editing_ranges_for(
 3857        &self,
 3858        selection: Range<text::Anchor>,
 3859        cx: &App,
 3860    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3861        if self.linked_edit_ranges.is_empty() {
 3862            return None;
 3863        }
 3864        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3865            selection.end.buffer_id.and_then(|end_buffer_id| {
 3866                if selection.start.buffer_id != Some(end_buffer_id) {
 3867                    return None;
 3868                }
 3869                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3870                let snapshot = buffer.read(cx).snapshot();
 3871                self.linked_edit_ranges
 3872                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3873                    .map(|ranges| (ranges, snapshot, buffer))
 3874            })?;
 3875        use text::ToOffset as TO;
 3876        // find offset from the start of current range to current cursor position
 3877        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3878
 3879        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3880        let start_difference = start_offset - start_byte_offset;
 3881        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3882        let end_difference = end_offset - start_byte_offset;
 3883        // Current range has associated linked ranges.
 3884        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3885        for range in linked_ranges.iter() {
 3886            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3887            let end_offset = start_offset + end_difference;
 3888            let start_offset = start_offset + start_difference;
 3889            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3890                continue;
 3891            }
 3892            if self.selections.disjoint_anchor_ranges().any(|s| {
 3893                if s.start.buffer_id != selection.start.buffer_id
 3894                    || s.end.buffer_id != selection.end.buffer_id
 3895                {
 3896                    return false;
 3897                }
 3898                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3899                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3900            }) {
 3901                continue;
 3902            }
 3903            let start = buffer_snapshot.anchor_after(start_offset);
 3904            let end = buffer_snapshot.anchor_after(end_offset);
 3905            linked_edits
 3906                .entry(buffer.clone())
 3907                .or_default()
 3908                .push(start..end);
 3909        }
 3910        Some(linked_edits)
 3911    }
 3912
 3913    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3914        let text: Arc<str> = text.into();
 3915
 3916        if self.read_only(cx) {
 3917            return;
 3918        }
 3919
 3920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3921
 3922        let selections = self.selections.all_adjusted(cx);
 3923        let mut bracket_inserted = false;
 3924        let mut edits = Vec::new();
 3925        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3926        let mut new_selections = Vec::with_capacity(selections.len());
 3927        let mut new_autoclose_regions = Vec::new();
 3928        let snapshot = self.buffer.read(cx).read(cx);
 3929        let mut clear_linked_edit_ranges = false;
 3930
 3931        for (selection, autoclose_region) in
 3932            self.selections_with_autoclose_regions(selections, &snapshot)
 3933        {
 3934            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3935                // Determine if the inserted text matches the opening or closing
 3936                // bracket of any of this language's bracket pairs.
 3937                let mut bracket_pair = None;
 3938                let mut is_bracket_pair_start = false;
 3939                let mut is_bracket_pair_end = false;
 3940                if !text.is_empty() {
 3941                    let mut bracket_pair_matching_end = None;
 3942                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3943                    //  and they are removing the character that triggered IME popup.
 3944                    for (pair, enabled) in scope.brackets() {
 3945                        if !pair.close && !pair.surround {
 3946                            continue;
 3947                        }
 3948
 3949                        if enabled && pair.start.ends_with(text.as_ref()) {
 3950                            let prefix_len = pair.start.len() - text.len();
 3951                            let preceding_text_matches_prefix = prefix_len == 0
 3952                                || (selection.start.column >= (prefix_len as u32)
 3953                                    && snapshot.contains_str_at(
 3954                                        Point::new(
 3955                                            selection.start.row,
 3956                                            selection.start.column - (prefix_len as u32),
 3957                                        ),
 3958                                        &pair.start[..prefix_len],
 3959                                    ));
 3960                            if preceding_text_matches_prefix {
 3961                                bracket_pair = Some(pair.clone());
 3962                                is_bracket_pair_start = true;
 3963                                break;
 3964                            }
 3965                        }
 3966                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3967                        {
 3968                            // take first bracket pair matching end, but don't break in case a later bracket
 3969                            // pair matches start
 3970                            bracket_pair_matching_end = Some(pair.clone());
 3971                        }
 3972                    }
 3973                    if let Some(end) = bracket_pair_matching_end
 3974                        && bracket_pair.is_none()
 3975                    {
 3976                        bracket_pair = Some(end);
 3977                        is_bracket_pair_end = true;
 3978                    }
 3979                }
 3980
 3981                if let Some(bracket_pair) = bracket_pair {
 3982                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3983                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3984                    let auto_surround =
 3985                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3986                    if selection.is_empty() {
 3987                        if is_bracket_pair_start {
 3988                            // If the inserted text is a suffix of an opening bracket and the
 3989                            // selection is preceded by the rest of the opening bracket, then
 3990                            // insert the closing bracket.
 3991                            let following_text_allows_autoclose = snapshot
 3992                                .chars_at(selection.start)
 3993                                .next()
 3994                                .map_or(true, |c| scope.should_autoclose_before(c));
 3995
 3996                            let preceding_text_allows_autoclose = selection.start.column == 0
 3997                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3998                                    true,
 3999                                    |c| {
 4000                                        bracket_pair.start != bracket_pair.end
 4001                                            || !snapshot
 4002                                                .char_classifier_at(selection.start)
 4003                                                .is_word(c)
 4004                                    },
 4005                                );
 4006
 4007                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4008                                && bracket_pair.start.len() == 1
 4009                            {
 4010                                let target = bracket_pair.start.chars().next().unwrap();
 4011                                let current_line_count = snapshot
 4012                                    .reversed_chars_at(selection.start)
 4013                                    .take_while(|&c| c != '\n')
 4014                                    .filter(|&c| c == target)
 4015                                    .count();
 4016                                current_line_count % 2 == 1
 4017                            } else {
 4018                                false
 4019                            };
 4020
 4021                            if autoclose
 4022                                && bracket_pair.close
 4023                                && following_text_allows_autoclose
 4024                                && preceding_text_allows_autoclose
 4025                                && !is_closing_quote
 4026                            {
 4027                                let anchor = snapshot.anchor_before(selection.end);
 4028                                new_selections.push((selection.map(|_| anchor), text.len()));
 4029                                new_autoclose_regions.push((
 4030                                    anchor,
 4031                                    text.len(),
 4032                                    selection.id,
 4033                                    bracket_pair.clone(),
 4034                                ));
 4035                                edits.push((
 4036                                    selection.range(),
 4037                                    format!("{}{}", text, bracket_pair.end).into(),
 4038                                ));
 4039                                bracket_inserted = true;
 4040                                continue;
 4041                            }
 4042                        }
 4043
 4044                        if let Some(region) = autoclose_region {
 4045                            // If the selection is followed by an auto-inserted closing bracket,
 4046                            // then don't insert that closing bracket again; just move the selection
 4047                            // past the closing bracket.
 4048                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4049                                && text.as_ref() == region.pair.end.as_str();
 4050                            if should_skip {
 4051                                let anchor = snapshot.anchor_after(selection.end);
 4052                                new_selections
 4053                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4054                                continue;
 4055                            }
 4056                        }
 4057
 4058                        let always_treat_brackets_as_autoclosed = snapshot
 4059                            .language_settings_at(selection.start, cx)
 4060                            .always_treat_brackets_as_autoclosed;
 4061                        if always_treat_brackets_as_autoclosed
 4062                            && is_bracket_pair_end
 4063                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4064                        {
 4065                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4066                            // and the inserted text is a closing bracket and the selection is followed
 4067                            // by the closing bracket then move the selection past the closing bracket.
 4068                            let anchor = snapshot.anchor_after(selection.end);
 4069                            new_selections.push((selection.map(|_| anchor), text.len()));
 4070                            continue;
 4071                        }
 4072                    }
 4073                    // If an opening bracket is 1 character long and is typed while
 4074                    // text is selected, then surround that text with the bracket pair.
 4075                    else if auto_surround
 4076                        && bracket_pair.surround
 4077                        && is_bracket_pair_start
 4078                        && bracket_pair.start.chars().count() == 1
 4079                    {
 4080                        edits.push((selection.start..selection.start, text.clone()));
 4081                        edits.push((
 4082                            selection.end..selection.end,
 4083                            bracket_pair.end.as_str().into(),
 4084                        ));
 4085                        bracket_inserted = true;
 4086                        new_selections.push((
 4087                            Selection {
 4088                                id: selection.id,
 4089                                start: snapshot.anchor_after(selection.start),
 4090                                end: snapshot.anchor_before(selection.end),
 4091                                reversed: selection.reversed,
 4092                                goal: selection.goal,
 4093                            },
 4094                            0,
 4095                        ));
 4096                        continue;
 4097                    }
 4098                }
 4099            }
 4100
 4101            if self.auto_replace_emoji_shortcode
 4102                && selection.is_empty()
 4103                && text.as_ref().ends_with(':')
 4104            {
 4105                if let Some(possible_emoji_short_code) =
 4106                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4107                {
 4108                    if !possible_emoji_short_code.is_empty() {
 4109                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4110                            let emoji_shortcode_start = Point::new(
 4111                                selection.start.row,
 4112                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4113                            );
 4114
 4115                            // Remove shortcode from buffer
 4116                            edits.push((
 4117                                emoji_shortcode_start..selection.start,
 4118                                "".to_string().into(),
 4119                            ));
 4120                            new_selections.push((
 4121                                Selection {
 4122                                    id: selection.id,
 4123                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4124                                    end: snapshot.anchor_before(selection.start),
 4125                                    reversed: selection.reversed,
 4126                                    goal: selection.goal,
 4127                                },
 4128                                0,
 4129                            ));
 4130
 4131                            // Insert emoji
 4132                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4133                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4134                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4135
 4136                            continue;
 4137                        }
 4138                    }
 4139                }
 4140            }
 4141
 4142            // If not handling any auto-close operation, then just replace the selected
 4143            // text with the given input and move the selection to the end of the
 4144            // newly inserted text.
 4145            let anchor = snapshot.anchor_after(selection.end);
 4146            if !self.linked_edit_ranges.is_empty() {
 4147                let start_anchor = snapshot.anchor_before(selection.start);
 4148
 4149                let is_word_char = text.chars().next().map_or(true, |char| {
 4150                    let classifier = snapshot
 4151                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4152                        .ignore_punctuation(true);
 4153                    classifier.is_word(char)
 4154                });
 4155
 4156                if is_word_char {
 4157                    if let Some(ranges) = self
 4158                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4159                    {
 4160                        for (buffer, edits) in ranges {
 4161                            linked_edits
 4162                                .entry(buffer.clone())
 4163                                .or_default()
 4164                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4165                        }
 4166                    }
 4167                } else {
 4168                    clear_linked_edit_ranges = true;
 4169                }
 4170            }
 4171
 4172            new_selections.push((selection.map(|_| anchor), 0));
 4173            edits.push((selection.start..selection.end, text.clone()));
 4174        }
 4175
 4176        drop(snapshot);
 4177
 4178        self.transact(window, cx, |this, window, cx| {
 4179            if clear_linked_edit_ranges {
 4180                this.linked_edit_ranges.clear();
 4181            }
 4182            let initial_buffer_versions =
 4183                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4184
 4185            this.buffer.update(cx, |buffer, cx| {
 4186                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4187            });
 4188            for (buffer, edits) in linked_edits {
 4189                buffer.update(cx, |buffer, cx| {
 4190                    let snapshot = buffer.snapshot();
 4191                    let edits = edits
 4192                        .into_iter()
 4193                        .map(|(range, text)| {
 4194                            use text::ToPoint as TP;
 4195                            let end_point = TP::to_point(&range.end, &snapshot);
 4196                            let start_point = TP::to_point(&range.start, &snapshot);
 4197                            (start_point..end_point, text)
 4198                        })
 4199                        .sorted_by_key(|(range, _)| range.start);
 4200                    buffer.edit(edits, None, cx);
 4201                })
 4202            }
 4203            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4204            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4205            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4206            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4207                .zip(new_selection_deltas)
 4208                .map(|(selection, delta)| Selection {
 4209                    id: selection.id,
 4210                    start: selection.start + delta,
 4211                    end: selection.end + delta,
 4212                    reversed: selection.reversed,
 4213                    goal: SelectionGoal::None,
 4214                })
 4215                .collect::<Vec<_>>();
 4216
 4217            let mut i = 0;
 4218            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4219                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4220                let start = map.buffer_snapshot.anchor_before(position);
 4221                let end = map.buffer_snapshot.anchor_after(position);
 4222                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4223                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4224                        Ordering::Less => i += 1,
 4225                        Ordering::Greater => break,
 4226                        Ordering::Equal => {
 4227                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4228                                Ordering::Less => i += 1,
 4229                                Ordering::Equal => break,
 4230                                Ordering::Greater => break,
 4231                            }
 4232                        }
 4233                    }
 4234                }
 4235                this.autoclose_regions.insert(
 4236                    i,
 4237                    AutocloseRegion {
 4238                        selection_id,
 4239                        range: start..end,
 4240                        pair,
 4241                    },
 4242                );
 4243            }
 4244
 4245            let had_active_inline_completion = this.has_active_inline_completion();
 4246            this.change_selections(
 4247                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4248                window,
 4249                cx,
 4250                |s| s.select(new_selections),
 4251            );
 4252
 4253            if !bracket_inserted {
 4254                if let Some(on_type_format_task) =
 4255                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4256                {
 4257                    on_type_format_task.detach_and_log_err(cx);
 4258                }
 4259            }
 4260
 4261            let editor_settings = EditorSettings::get_global(cx);
 4262            if bracket_inserted
 4263                && (editor_settings.auto_signature_help
 4264                    || editor_settings.show_signature_help_after_edits)
 4265            {
 4266                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4267            }
 4268
 4269            let trigger_in_words =
 4270                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4271            if this.hard_wrap.is_some() {
 4272                let latest: Range<Point> = this.selections.newest(cx).range();
 4273                if latest.is_empty()
 4274                    && this
 4275                        .buffer()
 4276                        .read(cx)
 4277                        .snapshot(cx)
 4278                        .line_len(MultiBufferRow(latest.start.row))
 4279                        == latest.start.column
 4280                {
 4281                    this.rewrap_impl(
 4282                        RewrapOptions {
 4283                            override_language_settings: true,
 4284                            preserve_existing_whitespace: true,
 4285                        },
 4286                        cx,
 4287                    )
 4288                }
 4289            }
 4290            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4291            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4292            this.refresh_inline_completion(true, false, window, cx);
 4293            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4294        });
 4295    }
 4296
 4297    fn find_possible_emoji_shortcode_at_position(
 4298        snapshot: &MultiBufferSnapshot,
 4299        position: Point,
 4300    ) -> Option<String> {
 4301        let mut chars = Vec::new();
 4302        let mut found_colon = false;
 4303        for char in snapshot.reversed_chars_at(position).take(100) {
 4304            // Found a possible emoji shortcode in the middle of the buffer
 4305            if found_colon {
 4306                if char.is_whitespace() {
 4307                    chars.reverse();
 4308                    return Some(chars.iter().collect());
 4309                }
 4310                // If the previous character is not a whitespace, we are in the middle of a word
 4311                // and we only want to complete the shortcode if the word is made up of other emojis
 4312                let mut containing_word = String::new();
 4313                for ch in snapshot
 4314                    .reversed_chars_at(position)
 4315                    .skip(chars.len() + 1)
 4316                    .take(100)
 4317                {
 4318                    if ch.is_whitespace() {
 4319                        break;
 4320                    }
 4321                    containing_word.push(ch);
 4322                }
 4323                let containing_word = containing_word.chars().rev().collect::<String>();
 4324                if util::word_consists_of_emojis(containing_word.as_str()) {
 4325                    chars.reverse();
 4326                    return Some(chars.iter().collect());
 4327                }
 4328            }
 4329
 4330            if char.is_whitespace() || !char.is_ascii() {
 4331                return None;
 4332            }
 4333            if char == ':' {
 4334                found_colon = true;
 4335            } else {
 4336                chars.push(char);
 4337            }
 4338        }
 4339        // Found a possible emoji shortcode at the beginning of the buffer
 4340        chars.reverse();
 4341        Some(chars.iter().collect())
 4342    }
 4343
 4344    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4346        self.transact(window, cx, |this, window, cx| {
 4347            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4348                let selections = this.selections.all::<usize>(cx);
 4349                let multi_buffer = this.buffer.read(cx);
 4350                let buffer = multi_buffer.snapshot(cx);
 4351                selections
 4352                    .iter()
 4353                    .map(|selection| {
 4354                        let start_point = selection.start.to_point(&buffer);
 4355                        let mut existing_indent =
 4356                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4357                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4358                        let start = selection.start;
 4359                        let end = selection.end;
 4360                        let selection_is_empty = start == end;
 4361                        let language_scope = buffer.language_scope_at(start);
 4362                        let (
 4363                            comment_delimiter,
 4364                            doc_delimiter,
 4365                            insert_extra_newline,
 4366                            indent_on_newline,
 4367                            indent_on_extra_newline,
 4368                        ) = if let Some(language) = &language_scope {
 4369                            let mut insert_extra_newline =
 4370                                insert_extra_newline_brackets(&buffer, start..end, language)
 4371                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4372
 4373                            // Comment extension on newline is allowed only for cursor selections
 4374                            let comment_delimiter = maybe!({
 4375                                if !selection_is_empty {
 4376                                    return None;
 4377                                }
 4378
 4379                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4380                                    return None;
 4381                                }
 4382
 4383                                let delimiters = language.line_comment_prefixes();
 4384                                let max_len_of_delimiter =
 4385                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4386                                let (snapshot, range) =
 4387                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4388
 4389                                let num_of_whitespaces = snapshot
 4390                                    .chars_for_range(range.clone())
 4391                                    .take_while(|c| c.is_whitespace())
 4392                                    .count();
 4393                                let comment_candidate = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .skip(num_of_whitespaces)
 4396                                    .take(max_len_of_delimiter)
 4397                                    .collect::<String>();
 4398                                let (delimiter, trimmed_len) = delimiters
 4399                                    .iter()
 4400                                    .filter_map(|delimiter| {
 4401                                        let prefix = delimiter.trim_end();
 4402                                        if comment_candidate.starts_with(prefix) {
 4403                                            Some((delimiter, prefix.len()))
 4404                                        } else {
 4405                                            None
 4406                                        }
 4407                                    })
 4408                                    .max_by_key(|(_, len)| *len)?;
 4409
 4410                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4411                                {
 4412                                    let block_start_trimmed = block_start.trim_end();
 4413                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4414                                        let line_content = snapshot
 4415                                            .chars_for_range(range)
 4416                                            .skip(num_of_whitespaces)
 4417                                            .take(block_start_trimmed.len())
 4418                                            .collect::<String>();
 4419
 4420                                        if line_content.starts_with(block_start_trimmed) {
 4421                                            return None;
 4422                                        }
 4423                                    }
 4424                                }
 4425
 4426                                let cursor_is_placed_after_comment_marker =
 4427                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4428                                if cursor_is_placed_after_comment_marker {
 4429                                    Some(delimiter.clone())
 4430                                } else {
 4431                                    None
 4432                                }
 4433                            });
 4434
 4435                            let mut indent_on_newline = IndentSize::spaces(0);
 4436                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4437
 4438                            let doc_delimiter = maybe!({
 4439                                if !selection_is_empty {
 4440                                    return None;
 4441                                }
 4442
 4443                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4444                                    return None;
 4445                                }
 4446
 4447                                let DocumentationConfig {
 4448                                    start: start_tag,
 4449                                    end: end_tag,
 4450                                    prefix: delimiter,
 4451                                    tab_size: len,
 4452                                } = language.documentation()?;
 4453
 4454                                let is_within_block_comment = buffer
 4455                                    .language_scope_at(start_point)
 4456                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4457                                if !is_within_block_comment {
 4458                                    return None;
 4459                                }
 4460
 4461                                let (snapshot, range) =
 4462                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4463
 4464                                let num_of_whitespaces = snapshot
 4465                                    .chars_for_range(range.clone())
 4466                                    .take_while(|c| c.is_whitespace())
 4467                                    .count();
 4468
 4469                                // 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.
 4470                                let column = start_point.column;
 4471                                let cursor_is_after_start_tag = {
 4472                                    let start_tag_len = start_tag.len();
 4473                                    let start_tag_line = snapshot
 4474                                        .chars_for_range(range.clone())
 4475                                        .skip(num_of_whitespaces)
 4476                                        .take(start_tag_len)
 4477                                        .collect::<String>();
 4478                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4479                                        num_of_whitespaces + start_tag_len <= column as usize
 4480                                    } else {
 4481                                        false
 4482                                    }
 4483                                };
 4484
 4485                                let cursor_is_after_delimiter = {
 4486                                    let delimiter_trim = delimiter.trim_end();
 4487                                    let delimiter_line = snapshot
 4488                                        .chars_for_range(range.clone())
 4489                                        .skip(num_of_whitespaces)
 4490                                        .take(delimiter_trim.len())
 4491                                        .collect::<String>();
 4492                                    if delimiter_line.starts_with(delimiter_trim) {
 4493                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4494                                    } else {
 4495                                        false
 4496                                    }
 4497                                };
 4498
 4499                                let cursor_is_before_end_tag_if_exists = {
 4500                                    let mut char_position = 0u32;
 4501                                    let mut end_tag_offset = None;
 4502
 4503                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4504                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4505                                            let chars_before_match =
 4506                                                chunk[..byte_pos].chars().count() as u32;
 4507                                            end_tag_offset =
 4508                                                Some(char_position + chars_before_match);
 4509                                            break 'outer;
 4510                                        }
 4511                                        char_position += chunk.chars().count() as u32;
 4512                                    }
 4513
 4514                                    if let Some(end_tag_offset) = end_tag_offset {
 4515                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4516                                        if cursor_is_after_start_tag {
 4517                                            if cursor_is_before_end_tag {
 4518                                                insert_extra_newline = true;
 4519                                            }
 4520                                            let cursor_is_at_start_of_end_tag =
 4521                                                column == end_tag_offset;
 4522                                            if cursor_is_at_start_of_end_tag {
 4523                                                indent_on_extra_newline.len = (*len).into();
 4524                                            }
 4525                                        }
 4526                                        cursor_is_before_end_tag
 4527                                    } else {
 4528                                        true
 4529                                    }
 4530                                };
 4531
 4532                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4533                                    && cursor_is_before_end_tag_if_exists
 4534                                {
 4535                                    if cursor_is_after_start_tag {
 4536                                        indent_on_newline.len = (*len).into();
 4537                                    }
 4538                                    Some(delimiter.clone())
 4539                                } else {
 4540                                    None
 4541                                }
 4542                            });
 4543
 4544                            (
 4545                                comment_delimiter,
 4546                                doc_delimiter,
 4547                                insert_extra_newline,
 4548                                indent_on_newline,
 4549                                indent_on_extra_newline,
 4550                            )
 4551                        } else {
 4552                            (
 4553                                None,
 4554                                None,
 4555                                false,
 4556                                IndentSize::default(),
 4557                                IndentSize::default(),
 4558                            )
 4559                        };
 4560
 4561                        let prevent_auto_indent = doc_delimiter.is_some();
 4562                        let delimiter = comment_delimiter.or(doc_delimiter);
 4563
 4564                        let capacity_for_delimiter =
 4565                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4566                        let mut new_text = String::with_capacity(
 4567                            1 + capacity_for_delimiter
 4568                                + existing_indent.len as usize
 4569                                + indent_on_newline.len as usize
 4570                                + indent_on_extra_newline.len as usize,
 4571                        );
 4572                        new_text.push('\n');
 4573                        new_text.extend(existing_indent.chars());
 4574                        new_text.extend(indent_on_newline.chars());
 4575
 4576                        if let Some(delimiter) = &delimiter {
 4577                            new_text.push_str(delimiter);
 4578                        }
 4579
 4580                        if insert_extra_newline {
 4581                            new_text.push('\n');
 4582                            new_text.extend(existing_indent.chars());
 4583                            new_text.extend(indent_on_extra_newline.chars());
 4584                        }
 4585
 4586                        let anchor = buffer.anchor_after(end);
 4587                        let new_selection = selection.map(|_| anchor);
 4588                        (
 4589                            ((start..end, new_text), prevent_auto_indent),
 4590                            (insert_extra_newline, new_selection),
 4591                        )
 4592                    })
 4593                    .unzip()
 4594            };
 4595
 4596            let mut auto_indent_edits = Vec::new();
 4597            let mut edits = Vec::new();
 4598            for (edit, prevent_auto_indent) in edits_with_flags {
 4599                if prevent_auto_indent {
 4600                    edits.push(edit);
 4601                } else {
 4602                    auto_indent_edits.push(edit);
 4603                }
 4604            }
 4605            if !edits.is_empty() {
 4606                this.edit(edits, cx);
 4607            }
 4608            if !auto_indent_edits.is_empty() {
 4609                this.edit_with_autoindent(auto_indent_edits, cx);
 4610            }
 4611
 4612            let buffer = this.buffer.read(cx).snapshot(cx);
 4613            let new_selections = selection_info
 4614                .into_iter()
 4615                .map(|(extra_newline_inserted, new_selection)| {
 4616                    let mut cursor = new_selection.end.to_point(&buffer);
 4617                    if extra_newline_inserted {
 4618                        cursor.row -= 1;
 4619                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4620                    }
 4621                    new_selection.map(|_| cursor)
 4622                })
 4623                .collect();
 4624
 4625            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4626            this.refresh_inline_completion(true, false, window, cx);
 4627        });
 4628    }
 4629
 4630    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4632
 4633        let buffer = self.buffer.read(cx);
 4634        let snapshot = buffer.snapshot(cx);
 4635
 4636        let mut edits = Vec::new();
 4637        let mut rows = Vec::new();
 4638
 4639        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4640            let cursor = selection.head();
 4641            let row = cursor.row;
 4642
 4643            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4644
 4645            let newline = "\n".to_string();
 4646            edits.push((start_of_line..start_of_line, newline));
 4647
 4648            rows.push(row + rows_inserted as u32);
 4649        }
 4650
 4651        self.transact(window, cx, |editor, window, cx| {
 4652            editor.edit(edits, cx);
 4653
 4654            editor.change_selections(Default::default(), window, cx, |s| {
 4655                let mut index = 0;
 4656                s.move_cursors_with(|map, _, _| {
 4657                    let row = rows[index];
 4658                    index += 1;
 4659
 4660                    let point = Point::new(row, 0);
 4661                    let boundary = map.next_line_boundary(point).1;
 4662                    let clipped = map.clip_point(boundary, Bias::Left);
 4663
 4664                    (clipped, SelectionGoal::None)
 4665                });
 4666            });
 4667
 4668            let mut indent_edits = Vec::new();
 4669            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4670            for row in rows {
 4671                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4672                for (row, indent) in indents {
 4673                    if indent.len == 0 {
 4674                        continue;
 4675                    }
 4676
 4677                    let text = match indent.kind {
 4678                        IndentKind::Space => " ".repeat(indent.len as usize),
 4679                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4680                    };
 4681                    let point = Point::new(row.0, 0);
 4682                    indent_edits.push((point..point, text));
 4683                }
 4684            }
 4685            editor.edit(indent_edits, cx);
 4686        });
 4687    }
 4688
 4689    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4691
 4692        let buffer = self.buffer.read(cx);
 4693        let snapshot = buffer.snapshot(cx);
 4694
 4695        let mut edits = Vec::new();
 4696        let mut rows = Vec::new();
 4697        let mut rows_inserted = 0;
 4698
 4699        for selection in self.selections.all_adjusted(cx) {
 4700            let cursor = selection.head();
 4701            let row = cursor.row;
 4702
 4703            let point = Point::new(row + 1, 0);
 4704            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4705
 4706            let newline = "\n".to_string();
 4707            edits.push((start_of_line..start_of_line, newline));
 4708
 4709            rows_inserted += 1;
 4710            rows.push(row + rows_inserted);
 4711        }
 4712
 4713        self.transact(window, cx, |editor, window, cx| {
 4714            editor.edit(edits, cx);
 4715
 4716            editor.change_selections(Default::default(), window, cx, |s| {
 4717                let mut index = 0;
 4718                s.move_cursors_with(|map, _, _| {
 4719                    let row = rows[index];
 4720                    index += 1;
 4721
 4722                    let point = Point::new(row, 0);
 4723                    let boundary = map.next_line_boundary(point).1;
 4724                    let clipped = map.clip_point(boundary, Bias::Left);
 4725
 4726                    (clipped, SelectionGoal::None)
 4727                });
 4728            });
 4729
 4730            let mut indent_edits = Vec::new();
 4731            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4732            for row in rows {
 4733                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4734                for (row, indent) in indents {
 4735                    if indent.len == 0 {
 4736                        continue;
 4737                    }
 4738
 4739                    let text = match indent.kind {
 4740                        IndentKind::Space => " ".repeat(indent.len as usize),
 4741                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4742                    };
 4743                    let point = Point::new(row.0, 0);
 4744                    indent_edits.push((point..point, text));
 4745                }
 4746            }
 4747            editor.edit(indent_edits, cx);
 4748        });
 4749    }
 4750
 4751    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4752        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4753            original_indent_columns: Vec::new(),
 4754        });
 4755        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4756    }
 4757
 4758    fn insert_with_autoindent_mode(
 4759        &mut self,
 4760        text: &str,
 4761        autoindent_mode: Option<AutoindentMode>,
 4762        window: &mut Window,
 4763        cx: &mut Context<Self>,
 4764    ) {
 4765        if self.read_only(cx) {
 4766            return;
 4767        }
 4768
 4769        let text: Arc<str> = text.into();
 4770        self.transact(window, cx, |this, window, cx| {
 4771            let old_selections = this.selections.all_adjusted(cx);
 4772            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4773                let anchors = {
 4774                    let snapshot = buffer.read(cx);
 4775                    old_selections
 4776                        .iter()
 4777                        .map(|s| {
 4778                            let anchor = snapshot.anchor_after(s.head());
 4779                            s.map(|_| anchor)
 4780                        })
 4781                        .collect::<Vec<_>>()
 4782                };
 4783                buffer.edit(
 4784                    old_selections
 4785                        .iter()
 4786                        .map(|s| (s.start..s.end, text.clone())),
 4787                    autoindent_mode,
 4788                    cx,
 4789                );
 4790                anchors
 4791            });
 4792
 4793            this.change_selections(Default::default(), window, cx, |s| {
 4794                s.select_anchors(selection_anchors);
 4795            });
 4796
 4797            cx.notify();
 4798        });
 4799    }
 4800
 4801    fn trigger_completion_on_input(
 4802        &mut self,
 4803        text: &str,
 4804        trigger_in_words: bool,
 4805        window: &mut Window,
 4806        cx: &mut Context<Self>,
 4807    ) {
 4808        let completions_source = self
 4809            .context_menu
 4810            .borrow()
 4811            .as_ref()
 4812            .and_then(|menu| match menu {
 4813                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4814                CodeContextMenu::CodeActions(_) => None,
 4815            });
 4816
 4817        match completions_source {
 4818            Some(CompletionsMenuSource::Words) => {
 4819                self.show_word_completions(&ShowWordCompletions, window, cx)
 4820            }
 4821            Some(CompletionsMenuSource::Normal)
 4822            | Some(CompletionsMenuSource::SnippetChoices)
 4823            | None
 4824                if self.is_completion_trigger(
 4825                    text,
 4826                    trigger_in_words,
 4827                    completions_source.is_some(),
 4828                    cx,
 4829                ) =>
 4830            {
 4831                self.show_completions(
 4832                    &ShowCompletions {
 4833                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4834                    },
 4835                    window,
 4836                    cx,
 4837                )
 4838            }
 4839            _ => {
 4840                self.hide_context_menu(window, cx);
 4841            }
 4842        }
 4843    }
 4844
 4845    fn is_completion_trigger(
 4846        &self,
 4847        text: &str,
 4848        trigger_in_words: bool,
 4849        menu_is_open: bool,
 4850        cx: &mut Context<Self>,
 4851    ) -> bool {
 4852        let position = self.selections.newest_anchor().head();
 4853        let multibuffer = self.buffer.read(cx);
 4854        let Some(buffer) = position
 4855            .buffer_id
 4856            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4857        else {
 4858            return false;
 4859        };
 4860
 4861        if let Some(completion_provider) = &self.completion_provider {
 4862            completion_provider.is_completion_trigger(
 4863                &buffer,
 4864                position.text_anchor,
 4865                text,
 4866                trigger_in_words,
 4867                menu_is_open,
 4868                cx,
 4869            )
 4870        } else {
 4871            false
 4872        }
 4873    }
 4874
 4875    /// If any empty selections is touching the start of its innermost containing autoclose
 4876    /// region, expand it to select the brackets.
 4877    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4878        let selections = self.selections.all::<usize>(cx);
 4879        let buffer = self.buffer.read(cx).read(cx);
 4880        let new_selections = self
 4881            .selections_with_autoclose_regions(selections, &buffer)
 4882            .map(|(mut selection, region)| {
 4883                if !selection.is_empty() {
 4884                    return selection;
 4885                }
 4886
 4887                if let Some(region) = region {
 4888                    let mut range = region.range.to_offset(&buffer);
 4889                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4890                        range.start -= region.pair.start.len();
 4891                        if buffer.contains_str_at(range.start, &region.pair.start)
 4892                            && buffer.contains_str_at(range.end, &region.pair.end)
 4893                        {
 4894                            range.end += region.pair.end.len();
 4895                            selection.start = range.start;
 4896                            selection.end = range.end;
 4897
 4898                            return selection;
 4899                        }
 4900                    }
 4901                }
 4902
 4903                let always_treat_brackets_as_autoclosed = buffer
 4904                    .language_settings_at(selection.start, cx)
 4905                    .always_treat_brackets_as_autoclosed;
 4906
 4907                if !always_treat_brackets_as_autoclosed {
 4908                    return selection;
 4909                }
 4910
 4911                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4912                    for (pair, enabled) in scope.brackets() {
 4913                        if !enabled || !pair.close {
 4914                            continue;
 4915                        }
 4916
 4917                        if buffer.contains_str_at(selection.start, &pair.end) {
 4918                            let pair_start_len = pair.start.len();
 4919                            if buffer.contains_str_at(
 4920                                selection.start.saturating_sub(pair_start_len),
 4921                                &pair.start,
 4922                            ) {
 4923                                selection.start -= pair_start_len;
 4924                                selection.end += pair.end.len();
 4925
 4926                                return selection;
 4927                            }
 4928                        }
 4929                    }
 4930                }
 4931
 4932                selection
 4933            })
 4934            .collect();
 4935
 4936        drop(buffer);
 4937        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4938            selections.select(new_selections)
 4939        });
 4940    }
 4941
 4942    /// Iterate the given selections, and for each one, find the smallest surrounding
 4943    /// autoclose region. This uses the ordering of the selections and the autoclose
 4944    /// regions to avoid repeated comparisons.
 4945    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4946        &'a self,
 4947        selections: impl IntoIterator<Item = Selection<D>>,
 4948        buffer: &'a MultiBufferSnapshot,
 4949    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4950        let mut i = 0;
 4951        let mut regions = self.autoclose_regions.as_slice();
 4952        selections.into_iter().map(move |selection| {
 4953            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4954
 4955            let mut enclosing = None;
 4956            while let Some(pair_state) = regions.get(i) {
 4957                if pair_state.range.end.to_offset(buffer) < range.start {
 4958                    regions = &regions[i + 1..];
 4959                    i = 0;
 4960                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4961                    break;
 4962                } else {
 4963                    if pair_state.selection_id == selection.id {
 4964                        enclosing = Some(pair_state);
 4965                    }
 4966                    i += 1;
 4967                }
 4968            }
 4969
 4970            (selection, enclosing)
 4971        })
 4972    }
 4973
 4974    /// Remove any autoclose regions that no longer contain their selection.
 4975    fn invalidate_autoclose_regions(
 4976        &mut self,
 4977        mut selections: &[Selection<Anchor>],
 4978        buffer: &MultiBufferSnapshot,
 4979    ) {
 4980        self.autoclose_regions.retain(|state| {
 4981            let mut i = 0;
 4982            while let Some(selection) = selections.get(i) {
 4983                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4984                    selections = &selections[1..];
 4985                    continue;
 4986                }
 4987                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4988                    break;
 4989                }
 4990                if selection.id == state.selection_id {
 4991                    return true;
 4992                } else {
 4993                    i += 1;
 4994                }
 4995            }
 4996            false
 4997        });
 4998    }
 4999
 5000    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5001        let offset = position.to_offset(buffer);
 5002        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5003        if offset > word_range.start && kind == Some(CharKind::Word) {
 5004            Some(
 5005                buffer
 5006                    .text_for_range(word_range.start..offset)
 5007                    .collect::<String>(),
 5008            )
 5009        } else {
 5010            None
 5011        }
 5012    }
 5013
 5014    pub fn toggle_inline_values(
 5015        &mut self,
 5016        _: &ToggleInlineValues,
 5017        _: &mut Window,
 5018        cx: &mut Context<Self>,
 5019    ) {
 5020        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5021
 5022        self.refresh_inline_values(cx);
 5023    }
 5024
 5025    pub fn toggle_inlay_hints(
 5026        &mut self,
 5027        _: &ToggleInlayHints,
 5028        _: &mut Window,
 5029        cx: &mut Context<Self>,
 5030    ) {
 5031        self.refresh_inlay_hints(
 5032            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5033            cx,
 5034        );
 5035    }
 5036
 5037    pub fn inlay_hints_enabled(&self) -> bool {
 5038        self.inlay_hint_cache.enabled
 5039    }
 5040
 5041    pub fn inline_values_enabled(&self) -> bool {
 5042        self.inline_value_cache.enabled
 5043    }
 5044
 5045    #[cfg(any(test, feature = "test-support"))]
 5046    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5047        self.display_map
 5048            .read(cx)
 5049            .current_inlays()
 5050            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5051            .cloned()
 5052            .collect()
 5053    }
 5054
 5055    #[cfg(any(test, feature = "test-support"))]
 5056    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5057        self.display_map
 5058            .read(cx)
 5059            .current_inlays()
 5060            .cloned()
 5061            .collect()
 5062    }
 5063
 5064    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5065        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5066            return;
 5067        }
 5068
 5069        let reason_description = reason.description();
 5070        let ignore_debounce = matches!(
 5071            reason,
 5072            InlayHintRefreshReason::SettingsChange(_)
 5073                | InlayHintRefreshReason::Toggle(_)
 5074                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5075                | InlayHintRefreshReason::ModifiersChanged(_)
 5076        );
 5077        let (invalidate_cache, required_languages) = match reason {
 5078            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5079                match self.inlay_hint_cache.modifiers_override(enabled) {
 5080                    Some(enabled) => {
 5081                        if enabled {
 5082                            (InvalidationStrategy::RefreshRequested, None)
 5083                        } else {
 5084                            self.splice_inlays(
 5085                                &self
 5086                                    .visible_inlay_hints(cx)
 5087                                    .iter()
 5088                                    .map(|inlay| inlay.id)
 5089                                    .collect::<Vec<InlayId>>(),
 5090                                Vec::new(),
 5091                                cx,
 5092                            );
 5093                            return;
 5094                        }
 5095                    }
 5096                    None => return,
 5097                }
 5098            }
 5099            InlayHintRefreshReason::Toggle(enabled) => {
 5100                if self.inlay_hint_cache.toggle(enabled) {
 5101                    if enabled {
 5102                        (InvalidationStrategy::RefreshRequested, None)
 5103                    } else {
 5104                        self.splice_inlays(
 5105                            &self
 5106                                .visible_inlay_hints(cx)
 5107                                .iter()
 5108                                .map(|inlay| inlay.id)
 5109                                .collect::<Vec<InlayId>>(),
 5110                            Vec::new(),
 5111                            cx,
 5112                        );
 5113                        return;
 5114                    }
 5115                } else {
 5116                    return;
 5117                }
 5118            }
 5119            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5120                match self.inlay_hint_cache.update_settings(
 5121                    &self.buffer,
 5122                    new_settings,
 5123                    self.visible_inlay_hints(cx),
 5124                    cx,
 5125                ) {
 5126                    ControlFlow::Break(Some(InlaySplice {
 5127                        to_remove,
 5128                        to_insert,
 5129                    })) => {
 5130                        self.splice_inlays(&to_remove, to_insert, cx);
 5131                        return;
 5132                    }
 5133                    ControlFlow::Break(None) => return,
 5134                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5135                }
 5136            }
 5137            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5138                if let Some(InlaySplice {
 5139                    to_remove,
 5140                    to_insert,
 5141                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5142                {
 5143                    self.splice_inlays(&to_remove, to_insert, cx);
 5144                }
 5145                self.display_map.update(cx, |display_map, _| {
 5146                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5147                });
 5148                return;
 5149            }
 5150            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5151            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5152                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5153            }
 5154            InlayHintRefreshReason::RefreshRequested => {
 5155                (InvalidationStrategy::RefreshRequested, None)
 5156            }
 5157        };
 5158
 5159        if let Some(InlaySplice {
 5160            to_remove,
 5161            to_insert,
 5162        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5163            reason_description,
 5164            self.visible_excerpts(required_languages.as_ref(), cx),
 5165            invalidate_cache,
 5166            ignore_debounce,
 5167            cx,
 5168        ) {
 5169            self.splice_inlays(&to_remove, to_insert, cx);
 5170        }
 5171    }
 5172
 5173    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5174        self.display_map
 5175            .read(cx)
 5176            .current_inlays()
 5177            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5178            .cloned()
 5179            .collect()
 5180    }
 5181
 5182    pub fn visible_excerpts(
 5183        &self,
 5184        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5185        cx: &mut Context<Editor>,
 5186    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5187        let Some(project) = self.project.as_ref() else {
 5188            return HashMap::default();
 5189        };
 5190        let project = project.read(cx);
 5191        let multi_buffer = self.buffer().read(cx);
 5192        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5193        let multi_buffer_visible_start = self
 5194            .scroll_manager
 5195            .anchor()
 5196            .anchor
 5197            .to_point(&multi_buffer_snapshot);
 5198        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5199            multi_buffer_visible_start
 5200                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5201            Bias::Left,
 5202        );
 5203        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5204        multi_buffer_snapshot
 5205            .range_to_buffer_ranges(multi_buffer_visible_range)
 5206            .into_iter()
 5207            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5208            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5209                let buffer_file = project::File::from_dyn(buffer.file())?;
 5210                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5211                let worktree_entry = buffer_worktree
 5212                    .read(cx)
 5213                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5214                if worktree_entry.is_ignored {
 5215                    return None;
 5216                }
 5217
 5218                let language = buffer.language()?;
 5219                if let Some(restrict_to_languages) = restrict_to_languages {
 5220                    if !restrict_to_languages.contains(language) {
 5221                        return None;
 5222                    }
 5223                }
 5224                Some((
 5225                    excerpt_id,
 5226                    (
 5227                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5228                        buffer.version().clone(),
 5229                        excerpt_visible_range,
 5230                    ),
 5231                ))
 5232            })
 5233            .collect()
 5234    }
 5235
 5236    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5237        TextLayoutDetails {
 5238            text_system: window.text_system().clone(),
 5239            editor_style: self.style.clone().unwrap(),
 5240            rem_size: window.rem_size(),
 5241            scroll_anchor: self.scroll_manager.anchor(),
 5242            visible_rows: self.visible_line_count(),
 5243            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5244        }
 5245    }
 5246
 5247    pub fn splice_inlays(
 5248        &self,
 5249        to_remove: &[InlayId],
 5250        to_insert: Vec<Inlay>,
 5251        cx: &mut Context<Self>,
 5252    ) {
 5253        self.display_map.update(cx, |display_map, cx| {
 5254            display_map.splice_inlays(to_remove, to_insert, cx)
 5255        });
 5256        cx.notify();
 5257    }
 5258
 5259    fn trigger_on_type_formatting(
 5260        &self,
 5261        input: String,
 5262        window: &mut Window,
 5263        cx: &mut Context<Self>,
 5264    ) -> Option<Task<Result<()>>> {
 5265        if input.len() != 1 {
 5266            return None;
 5267        }
 5268
 5269        let project = self.project.as_ref()?;
 5270        let position = self.selections.newest_anchor().head();
 5271        let (buffer, buffer_position) = self
 5272            .buffer
 5273            .read(cx)
 5274            .text_anchor_for_position(position, cx)?;
 5275
 5276        let settings = language_settings::language_settings(
 5277            buffer
 5278                .read(cx)
 5279                .language_at(buffer_position)
 5280                .map(|l| l.name()),
 5281            buffer.read(cx).file(),
 5282            cx,
 5283        );
 5284        if !settings.use_on_type_format {
 5285            return None;
 5286        }
 5287
 5288        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5289        // hence we do LSP request & edit on host side only — add formats to host's history.
 5290        let push_to_lsp_host_history = true;
 5291        // If this is not the host, append its history with new edits.
 5292        let push_to_client_history = project.read(cx).is_via_collab();
 5293
 5294        let on_type_formatting = project.update(cx, |project, cx| {
 5295            project.on_type_format(
 5296                buffer.clone(),
 5297                buffer_position,
 5298                input,
 5299                push_to_lsp_host_history,
 5300                cx,
 5301            )
 5302        });
 5303        Some(cx.spawn_in(window, async move |editor, cx| {
 5304            if let Some(transaction) = on_type_formatting.await? {
 5305                if push_to_client_history {
 5306                    buffer
 5307                        .update(cx, |buffer, _| {
 5308                            buffer.push_transaction(transaction, Instant::now());
 5309                            buffer.finalize_last_transaction();
 5310                        })
 5311                        .ok();
 5312                }
 5313                editor.update(cx, |editor, cx| {
 5314                    editor.refresh_document_highlights(cx);
 5315                })?;
 5316            }
 5317            Ok(())
 5318        }))
 5319    }
 5320
 5321    pub fn show_word_completions(
 5322        &mut self,
 5323        _: &ShowWordCompletions,
 5324        window: &mut Window,
 5325        cx: &mut Context<Self>,
 5326    ) {
 5327        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5328    }
 5329
 5330    pub fn show_completions(
 5331        &mut self,
 5332        options: &ShowCompletions,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5337    }
 5338
 5339    fn open_or_update_completions_menu(
 5340        &mut self,
 5341        requested_source: Option<CompletionsMenuSource>,
 5342        trigger: Option<&str>,
 5343        window: &mut Window,
 5344        cx: &mut Context<Self>,
 5345    ) {
 5346        if self.pending_rename.is_some() {
 5347            return;
 5348        }
 5349
 5350        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5351
 5352        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5353        // inserted and selected. To handle that case, the start of the selection is used so that
 5354        // the menu starts with all choices.
 5355        let position = self
 5356            .selections
 5357            .newest_anchor()
 5358            .start
 5359            .bias_right(&multibuffer_snapshot);
 5360        if position.diff_base_anchor.is_some() {
 5361            return;
 5362        }
 5363        let (buffer, buffer_position) =
 5364            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5365                output
 5366            } else {
 5367                return;
 5368            };
 5369        let buffer_snapshot = buffer.read(cx).snapshot();
 5370
 5371        let query: Option<Arc<String>> =
 5372            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5373
 5374        drop(multibuffer_snapshot);
 5375
 5376        let provider = match requested_source {
 5377            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5378            Some(CompletionsMenuSource::Words) => None,
 5379            Some(CompletionsMenuSource::SnippetChoices) => {
 5380                log::error!("bug: SnippetChoices requested_source is not handled");
 5381                None
 5382            }
 5383        };
 5384
 5385        let sort_completions = provider
 5386            .as_ref()
 5387            .map_or(false, |provider| provider.sort_completions());
 5388
 5389        let filter_completions = provider
 5390            .as_ref()
 5391            .map_or(true, |provider| provider.filter_completions());
 5392
 5393        let trigger_kind = match trigger {
 5394            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5395                CompletionTriggerKind::TRIGGER_CHARACTER
 5396            }
 5397            _ => CompletionTriggerKind::INVOKED,
 5398        };
 5399        let completion_context = CompletionContext {
 5400            trigger_character: trigger.and_then(|trigger| {
 5401                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5402                    Some(String::from(trigger))
 5403                } else {
 5404                    None
 5405                }
 5406            }),
 5407            trigger_kind,
 5408        };
 5409
 5410        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5411        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5412        // involve trigger chars, so this is skipped in that case.
 5413        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5414        {
 5415            let menu_is_open = matches!(
 5416                self.context_menu.borrow().as_ref(),
 5417                Some(CodeContextMenu::Completions(_))
 5418            );
 5419            if menu_is_open {
 5420                self.hide_context_menu(window, cx);
 5421            }
 5422        }
 5423
 5424        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5425            if filter_completions {
 5426                menu.filter(query.clone(), provider.clone(), window, cx);
 5427            }
 5428            // When `is_incomplete` is false, no need to re-query completions when the current query
 5429            // is a suffix of the initial query.
 5430            if !menu.is_incomplete {
 5431                // If the new query is a suffix of the old query (typing more characters) and
 5432                // the previous result was complete, the existing completions can be filtered.
 5433                //
 5434                // Note that this is always true for snippet completions.
 5435                let query_matches = match (&menu.initial_query, &query) {
 5436                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5437                    (None, _) => true,
 5438                    _ => false,
 5439                };
 5440                if query_matches {
 5441                    let position_matches = if menu.initial_position == position {
 5442                        true
 5443                    } else {
 5444                        let snapshot = self.buffer.read(cx).read(cx);
 5445                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5446                    };
 5447                    if position_matches {
 5448                        return;
 5449                    }
 5450                }
 5451            }
 5452        };
 5453
 5454        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5455            buffer_snapshot.surrounding_word(buffer_position, false)
 5456        {
 5457            let word_to_exclude = buffer_snapshot
 5458                .text_for_range(word_range.clone())
 5459                .collect::<String>();
 5460            (
 5461                buffer_snapshot.anchor_before(word_range.start)
 5462                    ..buffer_snapshot.anchor_after(buffer_position),
 5463                Some(word_to_exclude),
 5464            )
 5465        } else {
 5466            (buffer_position..buffer_position, None)
 5467        };
 5468
 5469        let language = buffer_snapshot
 5470            .language_at(buffer_position)
 5471            .map(|language| language.name());
 5472
 5473        let completion_settings =
 5474            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5475
 5476        let show_completion_documentation = buffer_snapshot
 5477            .settings_at(buffer_position, cx)
 5478            .show_completion_documentation;
 5479
 5480        // The document can be large, so stay in reasonable bounds when searching for words,
 5481        // otherwise completion pop-up might be slow to appear.
 5482        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5483        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5484        let min_word_search = buffer_snapshot.clip_point(
 5485            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5486            Bias::Left,
 5487        );
 5488        let max_word_search = buffer_snapshot.clip_point(
 5489            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5490            Bias::Right,
 5491        );
 5492        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5493            ..buffer_snapshot.point_to_offset(max_word_search);
 5494
 5495        let skip_digits = query
 5496            .as_ref()
 5497            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5498
 5499        let (mut words, provider_responses) = match &provider {
 5500            Some(provider) => {
 5501                let provider_responses = provider.completions(
 5502                    position.excerpt_id,
 5503                    &buffer,
 5504                    buffer_position,
 5505                    completion_context,
 5506                    window,
 5507                    cx,
 5508                );
 5509
 5510                let words = match completion_settings.words {
 5511                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5512                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5513                        .background_spawn(async move {
 5514                            buffer_snapshot.words_in_range(WordsQuery {
 5515                                fuzzy_contents: None,
 5516                                range: word_search_range,
 5517                                skip_digits,
 5518                            })
 5519                        }),
 5520                };
 5521
 5522                (words, provider_responses)
 5523            }
 5524            None => (
 5525                cx.background_spawn(async move {
 5526                    buffer_snapshot.words_in_range(WordsQuery {
 5527                        fuzzy_contents: None,
 5528                        range: word_search_range,
 5529                        skip_digits,
 5530                    })
 5531                }),
 5532                Task::ready(Ok(Vec::new())),
 5533            ),
 5534        };
 5535
 5536        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5537
 5538        let id = post_inc(&mut self.next_completion_id);
 5539        let task = cx.spawn_in(window, async move |editor, cx| {
 5540            let Ok(()) = editor.update(cx, |this, _| {
 5541                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5542            }) else {
 5543                return;
 5544            };
 5545
 5546            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5547            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5548            let mut completions = Vec::new();
 5549            let mut is_incomplete = false;
 5550            if let Some(provider_responses) = provider_responses.await.log_err() {
 5551                if !provider_responses.is_empty() {
 5552                    for response in provider_responses {
 5553                        completions.extend(response.completions);
 5554                        is_incomplete = is_incomplete || response.is_incomplete;
 5555                    }
 5556                    if completion_settings.words == WordsCompletionMode::Fallback {
 5557                        words = Task::ready(BTreeMap::default());
 5558                    }
 5559                }
 5560            }
 5561
 5562            let mut words = words.await;
 5563            if let Some(word_to_exclude) = &word_to_exclude {
 5564                words.remove(word_to_exclude);
 5565            }
 5566            for lsp_completion in &completions {
 5567                words.remove(&lsp_completion.new_text);
 5568            }
 5569            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5570                replace_range: word_replace_range.clone(),
 5571                new_text: word.clone(),
 5572                label: CodeLabel::plain(word, None),
 5573                icon_path: None,
 5574                documentation: None,
 5575                source: CompletionSource::BufferWord {
 5576                    word_range,
 5577                    resolved: false,
 5578                },
 5579                insert_text_mode: Some(InsertTextMode::AS_IS),
 5580                confirm: None,
 5581            }));
 5582
 5583            let menu = if completions.is_empty() {
 5584                None
 5585            } else {
 5586                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5587                    let languages = editor
 5588                        .workspace
 5589                        .as_ref()
 5590                        .and_then(|(workspace, _)| workspace.upgrade())
 5591                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5592                    let menu = CompletionsMenu::new(
 5593                        id,
 5594                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5595                        sort_completions,
 5596                        show_completion_documentation,
 5597                        position,
 5598                        query.clone(),
 5599                        is_incomplete,
 5600                        buffer.clone(),
 5601                        completions.into(),
 5602                        snippet_sort_order,
 5603                        languages,
 5604                        language,
 5605                        cx,
 5606                    );
 5607
 5608                    let query = if filter_completions { query } else { None };
 5609                    let matches_task = if let Some(query) = query {
 5610                        menu.do_async_filtering(query, cx)
 5611                    } else {
 5612                        Task::ready(menu.unfiltered_matches())
 5613                    };
 5614                    (menu, matches_task)
 5615                }) else {
 5616                    return;
 5617                };
 5618
 5619                let matches = matches_task.await;
 5620
 5621                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5622                    // Newer menu already set, so exit.
 5623                    match editor.context_menu.borrow().as_ref() {
 5624                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5625                            if prev_menu.id > id {
 5626                                return;
 5627                            }
 5628                        }
 5629                        _ => {}
 5630                    };
 5631
 5632                    // Only valid to take prev_menu because it the new menu is immediately set
 5633                    // below, or the menu is hidden.
 5634                    match editor.context_menu.borrow_mut().take() {
 5635                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5636                            let position_matches =
 5637                                if prev_menu.initial_position == menu.initial_position {
 5638                                    true
 5639                                } else {
 5640                                    let snapshot = editor.buffer.read(cx).read(cx);
 5641                                    prev_menu.initial_position.to_offset(&snapshot)
 5642                                        == menu.initial_position.to_offset(&snapshot)
 5643                                };
 5644                            if position_matches {
 5645                                // Preserve markdown cache before `set_filter_results` because it will
 5646                                // try to populate the documentation cache.
 5647                                menu.preserve_markdown_cache(prev_menu);
 5648                            }
 5649                        }
 5650                        _ => {}
 5651                    };
 5652
 5653                    menu.set_filter_results(matches, provider, window, cx);
 5654                }) else {
 5655                    return;
 5656                };
 5657
 5658                menu.visible().then_some(menu)
 5659            };
 5660
 5661            editor
 5662                .update_in(cx, |editor, window, cx| {
 5663                    if editor.focus_handle.is_focused(window) {
 5664                        if let Some(menu) = menu {
 5665                            *editor.context_menu.borrow_mut() =
 5666                                Some(CodeContextMenu::Completions(menu));
 5667
 5668                            crate::hover_popover::hide_hover(editor, cx);
 5669                            if editor.show_edit_predictions_in_menu() {
 5670                                editor.update_visible_inline_completion(window, cx);
 5671                            } else {
 5672                                editor.discard_inline_completion(false, cx);
 5673                            }
 5674
 5675                            cx.notify();
 5676                            return;
 5677                        }
 5678                    }
 5679
 5680                    if editor.completion_tasks.len() <= 1 {
 5681                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5682                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5683                        // If it was already hidden and we don't show inline completions in the menu, we should
 5684                        // also show the inline-completion when available.
 5685                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5686                            editor.update_visible_inline_completion(window, cx);
 5687                        }
 5688                    }
 5689                })
 5690                .ok();
 5691        });
 5692
 5693        self.completion_tasks.push((id, task));
 5694    }
 5695
 5696    #[cfg(feature = "test-support")]
 5697    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5698        let menu = self.context_menu.borrow();
 5699        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5700            let completions = menu.completions.borrow();
 5701            Some(completions.to_vec())
 5702        } else {
 5703            None
 5704        }
 5705    }
 5706
 5707    pub fn with_completions_menu_matching_id<R>(
 5708        &self,
 5709        id: CompletionId,
 5710        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5711    ) -> R {
 5712        let mut context_menu = self.context_menu.borrow_mut();
 5713        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5714            return f(None);
 5715        };
 5716        if completions_menu.id != id {
 5717            return f(None);
 5718        }
 5719        f(Some(completions_menu))
 5720    }
 5721
 5722    pub fn confirm_completion(
 5723        &mut self,
 5724        action: &ConfirmCompletion,
 5725        window: &mut Window,
 5726        cx: &mut Context<Self>,
 5727    ) -> Option<Task<Result<()>>> {
 5728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5729        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5730    }
 5731
 5732    pub fn confirm_completion_insert(
 5733        &mut self,
 5734        _: &ConfirmCompletionInsert,
 5735        window: &mut Window,
 5736        cx: &mut Context<Self>,
 5737    ) -> Option<Task<Result<()>>> {
 5738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5739        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5740    }
 5741
 5742    pub fn confirm_completion_replace(
 5743        &mut self,
 5744        _: &ConfirmCompletionReplace,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5749        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5750    }
 5751
 5752    pub fn compose_completion(
 5753        &mut self,
 5754        action: &ComposeCompletion,
 5755        window: &mut Window,
 5756        cx: &mut Context<Self>,
 5757    ) -> Option<Task<Result<()>>> {
 5758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5759        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5760    }
 5761
 5762    fn do_completion(
 5763        &mut self,
 5764        item_ix: Option<usize>,
 5765        intent: CompletionIntent,
 5766        window: &mut Window,
 5767        cx: &mut Context<Editor>,
 5768    ) -> Option<Task<Result<()>>> {
 5769        use language::ToOffset as _;
 5770
 5771        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5772        else {
 5773            return None;
 5774        };
 5775
 5776        let candidate_id = {
 5777            let entries = completions_menu.entries.borrow();
 5778            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5779            if self.show_edit_predictions_in_menu() {
 5780                self.discard_inline_completion(true, cx);
 5781            }
 5782            mat.candidate_id
 5783        };
 5784
 5785        let completion = completions_menu
 5786            .completions
 5787            .borrow()
 5788            .get(candidate_id)?
 5789            .clone();
 5790        cx.stop_propagation();
 5791
 5792        let buffer_handle = completions_menu.buffer.clone();
 5793
 5794        let CompletionEdit {
 5795            new_text,
 5796            snippet,
 5797            replace_range,
 5798        } = process_completion_for_edit(
 5799            &completion,
 5800            intent,
 5801            &buffer_handle,
 5802            &completions_menu.initial_position.text_anchor,
 5803            cx,
 5804        );
 5805
 5806        let buffer = buffer_handle.read(cx);
 5807        let snapshot = self.buffer.read(cx).snapshot(cx);
 5808        let newest_anchor = self.selections.newest_anchor();
 5809        let replace_range_multibuffer = {
 5810            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5811            let multibuffer_anchor = snapshot
 5812                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5813                .unwrap()
 5814                ..snapshot
 5815                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5816                    .unwrap();
 5817            multibuffer_anchor.start.to_offset(&snapshot)
 5818                ..multibuffer_anchor.end.to_offset(&snapshot)
 5819        };
 5820        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5821            return None;
 5822        }
 5823
 5824        let old_text = buffer
 5825            .text_for_range(replace_range.clone())
 5826            .collect::<String>();
 5827        let lookbehind = newest_anchor
 5828            .start
 5829            .text_anchor
 5830            .to_offset(buffer)
 5831            .saturating_sub(replace_range.start);
 5832        let lookahead = replace_range
 5833            .end
 5834            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5835        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5836        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5837
 5838        let selections = self.selections.all::<usize>(cx);
 5839        let mut ranges = Vec::new();
 5840        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5841
 5842        for selection in &selections {
 5843            let range = if selection.id == newest_anchor.id {
 5844                replace_range_multibuffer.clone()
 5845            } else {
 5846                let mut range = selection.range();
 5847
 5848                // if prefix is present, don't duplicate it
 5849                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5850                    range.start = range.start.saturating_sub(lookbehind);
 5851
 5852                    // if suffix is also present, mimic the newest cursor and replace it
 5853                    if selection.id != newest_anchor.id
 5854                        && snapshot.contains_str_at(range.end, suffix)
 5855                    {
 5856                        range.end += lookahead;
 5857                    }
 5858                }
 5859                range
 5860            };
 5861
 5862            ranges.push(range.clone());
 5863
 5864            if !self.linked_edit_ranges.is_empty() {
 5865                let start_anchor = snapshot.anchor_before(range.start);
 5866                let end_anchor = snapshot.anchor_after(range.end);
 5867                if let Some(ranges) = self
 5868                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5869                {
 5870                    for (buffer, edits) in ranges {
 5871                        linked_edits
 5872                            .entry(buffer.clone())
 5873                            .or_default()
 5874                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5875                    }
 5876                }
 5877            }
 5878        }
 5879
 5880        let common_prefix_len = old_text
 5881            .chars()
 5882            .zip(new_text.chars())
 5883            .take_while(|(a, b)| a == b)
 5884            .map(|(a, _)| a.len_utf8())
 5885            .sum::<usize>();
 5886
 5887        cx.emit(EditorEvent::InputHandled {
 5888            utf16_range_to_replace: None,
 5889            text: new_text[common_prefix_len..].into(),
 5890        });
 5891
 5892        self.transact(window, cx, |this, window, cx| {
 5893            if let Some(mut snippet) = snippet {
 5894                snippet.text = new_text.to_string();
 5895                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5896            } else {
 5897                this.buffer.update(cx, |buffer, cx| {
 5898                    let auto_indent = match completion.insert_text_mode {
 5899                        Some(InsertTextMode::AS_IS) => None,
 5900                        _ => this.autoindent_mode.clone(),
 5901                    };
 5902                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5903                    buffer.edit(edits, auto_indent, cx);
 5904                });
 5905            }
 5906            for (buffer, edits) in linked_edits {
 5907                buffer.update(cx, |buffer, cx| {
 5908                    let snapshot = buffer.snapshot();
 5909                    let edits = edits
 5910                        .into_iter()
 5911                        .map(|(range, text)| {
 5912                            use text::ToPoint as TP;
 5913                            let end_point = TP::to_point(&range.end, &snapshot);
 5914                            let start_point = TP::to_point(&range.start, &snapshot);
 5915                            (start_point..end_point, text)
 5916                        })
 5917                        .sorted_by_key(|(range, _)| range.start);
 5918                    buffer.edit(edits, None, cx);
 5919                })
 5920            }
 5921
 5922            this.refresh_inline_completion(true, false, window, cx);
 5923        });
 5924
 5925        let show_new_completions_on_confirm = completion
 5926            .confirm
 5927            .as_ref()
 5928            .map_or(false, |confirm| confirm(intent, window, cx));
 5929        if show_new_completions_on_confirm {
 5930            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5931        }
 5932
 5933        let provider = self.completion_provider.as_ref()?;
 5934        drop(completion);
 5935        let apply_edits = provider.apply_additional_edits_for_completion(
 5936            buffer_handle,
 5937            completions_menu.completions.clone(),
 5938            candidate_id,
 5939            true,
 5940            cx,
 5941        );
 5942
 5943        let editor_settings = EditorSettings::get_global(cx);
 5944        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5945            // After the code completion is finished, users often want to know what signatures are needed.
 5946            // so we should automatically call signature_help
 5947            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5948        }
 5949
 5950        Some(cx.foreground_executor().spawn(async move {
 5951            apply_edits.await?;
 5952            Ok(())
 5953        }))
 5954    }
 5955
 5956    pub fn toggle_code_actions(
 5957        &mut self,
 5958        action: &ToggleCodeActions,
 5959        window: &mut Window,
 5960        cx: &mut Context<Self>,
 5961    ) {
 5962        let quick_launch = action.quick_launch;
 5963        let mut context_menu = self.context_menu.borrow_mut();
 5964        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5965            if code_actions.deployed_from == action.deployed_from {
 5966                // Toggle if we're selecting the same one
 5967                *context_menu = None;
 5968                cx.notify();
 5969                return;
 5970            } else {
 5971                // Otherwise, clear it and start a new one
 5972                *context_menu = None;
 5973                cx.notify();
 5974            }
 5975        }
 5976        drop(context_menu);
 5977        let snapshot = self.snapshot(window, cx);
 5978        let deployed_from = action.deployed_from.clone();
 5979        let action = action.clone();
 5980        self.completion_tasks.clear();
 5981        self.discard_inline_completion(false, cx);
 5982
 5983        let multibuffer_point = match &action.deployed_from {
 5984            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5985                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5986            }
 5987            _ => self.selections.newest::<Point>(cx).head(),
 5988        };
 5989        let Some((buffer, buffer_row)) = snapshot
 5990            .buffer_snapshot
 5991            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5992            .and_then(|(buffer_snapshot, range)| {
 5993                self.buffer()
 5994                    .read(cx)
 5995                    .buffer(buffer_snapshot.remote_id())
 5996                    .map(|buffer| (buffer, range.start.row))
 5997            })
 5998        else {
 5999            return;
 6000        };
 6001        let buffer_id = buffer.read(cx).remote_id();
 6002        let tasks = self
 6003            .tasks
 6004            .get(&(buffer_id, buffer_row))
 6005            .map(|t| Arc::new(t.to_owned()));
 6006
 6007        if !self.focus_handle.is_focused(window) {
 6008            return;
 6009        }
 6010        let project = self.project.clone();
 6011
 6012        let code_actions_task = match deployed_from {
 6013            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6014            _ => self.code_actions(buffer_row, window, cx),
 6015        };
 6016
 6017        let runnable_task = match deployed_from {
 6018            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6019            _ => {
 6020                let mut task_context_task = Task::ready(None);
 6021                if let Some(tasks) = &tasks {
 6022                    if let Some(project) = project {
 6023                        task_context_task =
 6024                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6025                    }
 6026                }
 6027
 6028                cx.spawn_in(window, {
 6029                    let buffer = buffer.clone();
 6030                    async move |editor, cx| {
 6031                        let task_context = task_context_task.await;
 6032
 6033                        let resolved_tasks =
 6034                            tasks
 6035                                .zip(task_context.clone())
 6036                                .map(|(tasks, task_context)| ResolvedTasks {
 6037                                    templates: tasks.resolve(&task_context).collect(),
 6038                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6039                                        multibuffer_point.row,
 6040                                        tasks.column,
 6041                                    )),
 6042                                });
 6043                        let debug_scenarios = editor
 6044                            .update(cx, |editor, cx| {
 6045                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6046                            })?
 6047                            .await;
 6048                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6049                    }
 6050                })
 6051            }
 6052        };
 6053
 6054        cx.spawn_in(window, async move |editor, cx| {
 6055            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6056            let code_actions = code_actions_task.await;
 6057            let spawn_straight_away = quick_launch
 6058                && resolved_tasks
 6059                    .as_ref()
 6060                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6061                && code_actions
 6062                    .as_ref()
 6063                    .map_or(true, |actions| actions.is_empty())
 6064                && debug_scenarios.is_empty();
 6065
 6066            editor.update_in(cx, |editor, window, cx| {
 6067                crate::hover_popover::hide_hover(editor, cx);
 6068                let actions = CodeActionContents::new(
 6069                    resolved_tasks,
 6070                    code_actions,
 6071                    debug_scenarios,
 6072                    task_context.unwrap_or_default(),
 6073                );
 6074
 6075                // Don't show the menu if there are no actions available
 6076                if actions.is_empty() {
 6077                    cx.notify();
 6078                    return Task::ready(Ok(()));
 6079                }
 6080
 6081                *editor.context_menu.borrow_mut() =
 6082                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6083                        buffer,
 6084                        actions,
 6085                        selected_item: Default::default(),
 6086                        scroll_handle: UniformListScrollHandle::default(),
 6087                        deployed_from,
 6088                    }));
 6089                cx.notify();
 6090                if spawn_straight_away {
 6091                    if let Some(task) = editor.confirm_code_action(
 6092                        &ConfirmCodeAction { item_ix: Some(0) },
 6093                        window,
 6094                        cx,
 6095                    ) {
 6096                        return task;
 6097                    }
 6098                }
 6099
 6100                Task::ready(Ok(()))
 6101            })
 6102        })
 6103        .detach_and_log_err(cx);
 6104    }
 6105
 6106    fn debug_scenarios(
 6107        &mut self,
 6108        resolved_tasks: &Option<ResolvedTasks>,
 6109        buffer: &Entity<Buffer>,
 6110        cx: &mut App,
 6111    ) -> Task<Vec<task::DebugScenario>> {
 6112        maybe!({
 6113            let project = self.project.as_ref()?;
 6114            let dap_store = project.read(cx).dap_store();
 6115            let mut scenarios = vec![];
 6116            let resolved_tasks = resolved_tasks.as_ref()?;
 6117            let buffer = buffer.read(cx);
 6118            let language = buffer.language()?;
 6119            let file = buffer.file();
 6120            let debug_adapter = language_settings(language.name().into(), file, cx)
 6121                .debuggers
 6122                .first()
 6123                .map(SharedString::from)
 6124                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6125
 6126            dap_store.update(cx, |dap_store, cx| {
 6127                for (_, task) in &resolved_tasks.templates {
 6128                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6129                        task.original_task().clone(),
 6130                        debug_adapter.clone().into(),
 6131                        task.display_label().to_owned().into(),
 6132                        cx,
 6133                    );
 6134                    scenarios.push(maybe_scenario);
 6135                }
 6136            });
 6137            Some(cx.background_spawn(async move {
 6138                let scenarios = futures::future::join_all(scenarios)
 6139                    .await
 6140                    .into_iter()
 6141                    .flatten()
 6142                    .collect::<Vec<_>>();
 6143                scenarios
 6144            }))
 6145        })
 6146        .unwrap_or_else(|| Task::ready(vec![]))
 6147    }
 6148
 6149    fn code_actions(
 6150        &mut self,
 6151        buffer_row: u32,
 6152        window: &mut Window,
 6153        cx: &mut Context<Self>,
 6154    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6155        let mut task = self.code_actions_task.take();
 6156        cx.spawn_in(window, async move |editor, cx| {
 6157            while let Some(prev_task) = task {
 6158                prev_task.await.log_err();
 6159                task = editor
 6160                    .update(cx, |this, _| this.code_actions_task.take())
 6161                    .ok()?;
 6162            }
 6163
 6164            editor
 6165                .update(cx, |editor, cx| {
 6166                    editor
 6167                        .available_code_actions
 6168                        .clone()
 6169                        .and_then(|(location, code_actions)| {
 6170                            let snapshot = location.buffer.read(cx).snapshot();
 6171                            let point_range = location.range.to_point(&snapshot);
 6172                            let point_range = point_range.start.row..=point_range.end.row;
 6173                            if point_range.contains(&buffer_row) {
 6174                                Some(code_actions)
 6175                            } else {
 6176                                None
 6177                            }
 6178                        })
 6179                })
 6180                .ok()
 6181                .flatten()
 6182        })
 6183    }
 6184
 6185    pub fn confirm_code_action(
 6186        &mut self,
 6187        action: &ConfirmCodeAction,
 6188        window: &mut Window,
 6189        cx: &mut Context<Self>,
 6190    ) -> Option<Task<Result<()>>> {
 6191        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6192
 6193        let actions_menu =
 6194            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6195                menu
 6196            } else {
 6197                return None;
 6198            };
 6199
 6200        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6201        let action = actions_menu.actions.get(action_ix)?;
 6202        let title = action.label();
 6203        let buffer = actions_menu.buffer;
 6204        let workspace = self.workspace()?;
 6205
 6206        match action {
 6207            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6208                workspace.update(cx, |workspace, cx| {
 6209                    workspace.schedule_resolved_task(
 6210                        task_source_kind,
 6211                        resolved_task,
 6212                        false,
 6213                        window,
 6214                        cx,
 6215                    );
 6216
 6217                    Some(Task::ready(Ok(())))
 6218                })
 6219            }
 6220            CodeActionsItem::CodeAction {
 6221                excerpt_id,
 6222                action,
 6223                provider,
 6224            } => {
 6225                let apply_code_action =
 6226                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6227                let workspace = workspace.downgrade();
 6228                Some(cx.spawn_in(window, async move |editor, cx| {
 6229                    let project_transaction = apply_code_action.await?;
 6230                    Self::open_project_transaction(
 6231                        &editor,
 6232                        workspace,
 6233                        project_transaction,
 6234                        title,
 6235                        cx,
 6236                    )
 6237                    .await
 6238                }))
 6239            }
 6240            CodeActionsItem::DebugScenario(scenario) => {
 6241                let context = actions_menu.actions.context.clone();
 6242
 6243                workspace.update(cx, |workspace, cx| {
 6244                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6245                    workspace.start_debug_session(
 6246                        scenario,
 6247                        context,
 6248                        Some(buffer),
 6249                        None,
 6250                        window,
 6251                        cx,
 6252                    );
 6253                });
 6254                Some(Task::ready(Ok(())))
 6255            }
 6256        }
 6257    }
 6258
 6259    pub async fn open_project_transaction(
 6260        this: &WeakEntity<Editor>,
 6261        workspace: WeakEntity<Workspace>,
 6262        transaction: ProjectTransaction,
 6263        title: String,
 6264        cx: &mut AsyncWindowContext,
 6265    ) -> Result<()> {
 6266        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6267        cx.update(|_, cx| {
 6268            entries.sort_unstable_by_key(|(buffer, _)| {
 6269                buffer.read(cx).file().map(|f| f.path().clone())
 6270            });
 6271        })?;
 6272
 6273        // If the project transaction's edits are all contained within this editor, then
 6274        // avoid opening a new editor to display them.
 6275
 6276        if let Some((buffer, transaction)) = entries.first() {
 6277            if entries.len() == 1 {
 6278                let excerpt = this.update(cx, |editor, cx| {
 6279                    editor
 6280                        .buffer()
 6281                        .read(cx)
 6282                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6283                })?;
 6284                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6285                    if excerpted_buffer == *buffer {
 6286                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6287                            let excerpt_range = excerpt_range.to_offset(buffer);
 6288                            buffer
 6289                                .edited_ranges_for_transaction::<usize>(transaction)
 6290                                .all(|range| {
 6291                                    excerpt_range.start <= range.start
 6292                                        && excerpt_range.end >= range.end
 6293                                })
 6294                        })?;
 6295
 6296                        if all_edits_within_excerpt {
 6297                            return Ok(());
 6298                        }
 6299                    }
 6300                }
 6301            }
 6302        } else {
 6303            return Ok(());
 6304        }
 6305
 6306        let mut ranges_to_highlight = Vec::new();
 6307        let excerpt_buffer = cx.new(|cx| {
 6308            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6309            for (buffer_handle, transaction) in &entries {
 6310                let edited_ranges = buffer_handle
 6311                    .read(cx)
 6312                    .edited_ranges_for_transaction::<Point>(transaction)
 6313                    .collect::<Vec<_>>();
 6314                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6315                    PathKey::for_buffer(buffer_handle, cx),
 6316                    buffer_handle.clone(),
 6317                    edited_ranges,
 6318                    DEFAULT_MULTIBUFFER_CONTEXT,
 6319                    cx,
 6320                );
 6321
 6322                ranges_to_highlight.extend(ranges);
 6323            }
 6324            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6325            multibuffer
 6326        })?;
 6327
 6328        workspace.update_in(cx, |workspace, window, cx| {
 6329            let project = workspace.project().clone();
 6330            let editor =
 6331                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6332            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6333            editor.update(cx, |editor, cx| {
 6334                editor.highlight_background::<Self>(
 6335                    &ranges_to_highlight,
 6336                    |theme| theme.colors().editor_highlighted_line_background,
 6337                    cx,
 6338                );
 6339            });
 6340        })?;
 6341
 6342        Ok(())
 6343    }
 6344
 6345    pub fn clear_code_action_providers(&mut self) {
 6346        self.code_action_providers.clear();
 6347        self.available_code_actions.take();
 6348    }
 6349
 6350    pub fn add_code_action_provider(
 6351        &mut self,
 6352        provider: Rc<dyn CodeActionProvider>,
 6353        window: &mut Window,
 6354        cx: &mut Context<Self>,
 6355    ) {
 6356        if self
 6357            .code_action_providers
 6358            .iter()
 6359            .any(|existing_provider| existing_provider.id() == provider.id())
 6360        {
 6361            return;
 6362        }
 6363
 6364        self.code_action_providers.push(provider);
 6365        self.refresh_code_actions(window, cx);
 6366    }
 6367
 6368    pub fn remove_code_action_provider(
 6369        &mut self,
 6370        id: Arc<str>,
 6371        window: &mut Window,
 6372        cx: &mut Context<Self>,
 6373    ) {
 6374        self.code_action_providers
 6375            .retain(|provider| provider.id() != id);
 6376        self.refresh_code_actions(window, cx);
 6377    }
 6378
 6379    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6380        !self.code_action_providers.is_empty()
 6381            && EditorSettings::get_global(cx).toolbar.code_actions
 6382    }
 6383
 6384    pub fn has_available_code_actions(&self) -> bool {
 6385        self.available_code_actions
 6386            .as_ref()
 6387            .is_some_and(|(_, actions)| !actions.is_empty())
 6388    }
 6389
 6390    fn render_inline_code_actions(
 6391        &self,
 6392        icon_size: ui::IconSize,
 6393        display_row: DisplayRow,
 6394        is_active: bool,
 6395        cx: &mut Context<Self>,
 6396    ) -> AnyElement {
 6397        let show_tooltip = !self.context_menu_visible();
 6398        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6399            .icon_size(icon_size)
 6400            .shape(ui::IconButtonShape::Square)
 6401            .style(ButtonStyle::Transparent)
 6402            .icon_color(ui::Color::Hidden)
 6403            .toggle_state(is_active)
 6404            .when(show_tooltip, |this| {
 6405                this.tooltip({
 6406                    let focus_handle = self.focus_handle.clone();
 6407                    move |window, cx| {
 6408                        Tooltip::for_action_in(
 6409                            "Toggle Code Actions",
 6410                            &ToggleCodeActions {
 6411                                deployed_from: None,
 6412                                quick_launch: false,
 6413                            },
 6414                            &focus_handle,
 6415                            window,
 6416                            cx,
 6417                        )
 6418                    }
 6419                })
 6420            })
 6421            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6422                window.focus(&editor.focus_handle(cx));
 6423                editor.toggle_code_actions(
 6424                    &crate::actions::ToggleCodeActions {
 6425                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6426                            display_row,
 6427                        )),
 6428                        quick_launch: false,
 6429                    },
 6430                    window,
 6431                    cx,
 6432                );
 6433            }))
 6434            .into_any_element()
 6435    }
 6436
 6437    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6438        &self.context_menu
 6439    }
 6440
 6441    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6442        let newest_selection = self.selections.newest_anchor().clone();
 6443        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6444        let buffer = self.buffer.read(cx);
 6445        if newest_selection.head().diff_base_anchor.is_some() {
 6446            return None;
 6447        }
 6448        let (start_buffer, start) =
 6449            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6450        let (end_buffer, end) =
 6451            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6452        if start_buffer != end_buffer {
 6453            return None;
 6454        }
 6455
 6456        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6457            cx.background_executor()
 6458                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6459                .await;
 6460
 6461            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6462                let providers = this.code_action_providers.clone();
 6463                let tasks = this
 6464                    .code_action_providers
 6465                    .iter()
 6466                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6467                    .collect::<Vec<_>>();
 6468                (providers, tasks)
 6469            })?;
 6470
 6471            let mut actions = Vec::new();
 6472            for (provider, provider_actions) in
 6473                providers.into_iter().zip(future::join_all(tasks).await)
 6474            {
 6475                if let Some(provider_actions) = provider_actions.log_err() {
 6476                    actions.extend(provider_actions.into_iter().map(|action| {
 6477                        AvailableCodeAction {
 6478                            excerpt_id: newest_selection.start.excerpt_id,
 6479                            action,
 6480                            provider: provider.clone(),
 6481                        }
 6482                    }));
 6483                }
 6484            }
 6485
 6486            this.update(cx, |this, cx| {
 6487                this.available_code_actions = if actions.is_empty() {
 6488                    None
 6489                } else {
 6490                    Some((
 6491                        Location {
 6492                            buffer: start_buffer,
 6493                            range: start..end,
 6494                        },
 6495                        actions.into(),
 6496                    ))
 6497                };
 6498                cx.notify();
 6499            })
 6500        }));
 6501        None
 6502    }
 6503
 6504    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6505        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6506            self.show_git_blame_inline = false;
 6507
 6508            self.show_git_blame_inline_delay_task =
 6509                Some(cx.spawn_in(window, async move |this, cx| {
 6510                    cx.background_executor().timer(delay).await;
 6511
 6512                    this.update(cx, |this, cx| {
 6513                        this.show_git_blame_inline = true;
 6514                        cx.notify();
 6515                    })
 6516                    .log_err();
 6517                }));
 6518        }
 6519    }
 6520
 6521    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6522        let snapshot = self.snapshot(window, cx);
 6523        let cursor = self.selections.newest::<Point>(cx).head();
 6524        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6525        else {
 6526            return;
 6527        };
 6528
 6529        let Some(blame) = self.blame.as_ref() else {
 6530            return;
 6531        };
 6532
 6533        let row_info = RowInfo {
 6534            buffer_id: Some(buffer.remote_id()),
 6535            buffer_row: Some(point.row),
 6536            ..Default::default()
 6537        };
 6538        let Some(blame_entry) = blame
 6539            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6540            .flatten()
 6541        else {
 6542            return;
 6543        };
 6544
 6545        let anchor = self.selections.newest_anchor().head();
 6546        let position = self.to_pixel_point(anchor, &snapshot, window);
 6547        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6548            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6549        };
 6550    }
 6551
 6552    fn show_blame_popover(
 6553        &mut self,
 6554        blame_entry: &BlameEntry,
 6555        position: gpui::Point<Pixels>,
 6556        ignore_timeout: bool,
 6557        cx: &mut Context<Self>,
 6558    ) {
 6559        if let Some(state) = &mut self.inline_blame_popover {
 6560            state.hide_task.take();
 6561        } else {
 6562            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6563            let blame_entry = blame_entry.clone();
 6564            let show_task = cx.spawn(async move |editor, cx| {
 6565                if !ignore_timeout {
 6566                    cx.background_executor()
 6567                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6568                        .await;
 6569                }
 6570                editor
 6571                    .update(cx, |editor, cx| {
 6572                        editor.inline_blame_popover_show_task.take();
 6573                        let Some(blame) = editor.blame.as_ref() else {
 6574                            return;
 6575                        };
 6576                        let blame = blame.read(cx);
 6577                        let details = blame.details_for_entry(&blame_entry);
 6578                        let markdown = cx.new(|cx| {
 6579                            Markdown::new(
 6580                                details
 6581                                    .as_ref()
 6582                                    .map(|message| message.message.clone())
 6583                                    .unwrap_or_default(),
 6584                                None,
 6585                                None,
 6586                                cx,
 6587                            )
 6588                        });
 6589                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6590                            position,
 6591                            hide_task: None,
 6592                            popover_bounds: None,
 6593                            popover_state: InlineBlamePopoverState {
 6594                                scroll_handle: ScrollHandle::new(),
 6595                                commit_message: details,
 6596                                markdown,
 6597                            },
 6598                            keyboard_grace: ignore_timeout,
 6599                        });
 6600                        cx.notify();
 6601                    })
 6602                    .ok();
 6603            });
 6604            self.inline_blame_popover_show_task = Some(show_task);
 6605        }
 6606    }
 6607
 6608    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6609        self.inline_blame_popover_show_task.take();
 6610        if let Some(state) = &mut self.inline_blame_popover {
 6611            let hide_task = cx.spawn(async move |editor, cx| {
 6612                cx.background_executor()
 6613                    .timer(std::time::Duration::from_millis(100))
 6614                    .await;
 6615                editor
 6616                    .update(cx, |editor, cx| {
 6617                        editor.inline_blame_popover.take();
 6618                        cx.notify();
 6619                    })
 6620                    .ok();
 6621            });
 6622            state.hide_task = Some(hide_task);
 6623        }
 6624    }
 6625
 6626    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6627        if self.pending_rename.is_some() {
 6628            return None;
 6629        }
 6630
 6631        let provider = self.semantics_provider.clone()?;
 6632        let buffer = self.buffer.read(cx);
 6633        let newest_selection = self.selections.newest_anchor().clone();
 6634        let cursor_position = newest_selection.head();
 6635        let (cursor_buffer, cursor_buffer_position) =
 6636            buffer.text_anchor_for_position(cursor_position, cx)?;
 6637        let (tail_buffer, tail_buffer_position) =
 6638            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6639        if cursor_buffer != tail_buffer {
 6640            return None;
 6641        }
 6642
 6643        let snapshot = cursor_buffer.read(cx).snapshot();
 6644        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6645        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6646        if start_word_range != end_word_range {
 6647            self.document_highlights_task.take();
 6648            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6649            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6650            return None;
 6651        }
 6652
 6653        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6654        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6655            cx.background_executor()
 6656                .timer(Duration::from_millis(debounce))
 6657                .await;
 6658
 6659            let highlights = if let Some(highlights) = cx
 6660                .update(|cx| {
 6661                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6662                })
 6663                .ok()
 6664                .flatten()
 6665            {
 6666                highlights.await.log_err()
 6667            } else {
 6668                None
 6669            };
 6670
 6671            if let Some(highlights) = highlights {
 6672                this.update(cx, |this, cx| {
 6673                    if this.pending_rename.is_some() {
 6674                        return;
 6675                    }
 6676
 6677                    let buffer_id = cursor_position.buffer_id;
 6678                    let buffer = this.buffer.read(cx);
 6679                    if !buffer
 6680                        .text_anchor_for_position(cursor_position, cx)
 6681                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6682                    {
 6683                        return;
 6684                    }
 6685
 6686                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6687                    let mut write_ranges = Vec::new();
 6688                    let mut read_ranges = Vec::new();
 6689                    for highlight in highlights {
 6690                        for (excerpt_id, excerpt_range) in
 6691                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6692                        {
 6693                            let start = highlight
 6694                                .range
 6695                                .start
 6696                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6697                            let end = highlight
 6698                                .range
 6699                                .end
 6700                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6701                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6702                                continue;
 6703                            }
 6704
 6705                            let range = Anchor {
 6706                                buffer_id,
 6707                                excerpt_id,
 6708                                text_anchor: start,
 6709                                diff_base_anchor: None,
 6710                            }..Anchor {
 6711                                buffer_id,
 6712                                excerpt_id,
 6713                                text_anchor: end,
 6714                                diff_base_anchor: None,
 6715                            };
 6716                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6717                                write_ranges.push(range);
 6718                            } else {
 6719                                read_ranges.push(range);
 6720                            }
 6721                        }
 6722                    }
 6723
 6724                    this.highlight_background::<DocumentHighlightRead>(
 6725                        &read_ranges,
 6726                        |theme| theme.colors().editor_document_highlight_read_background,
 6727                        cx,
 6728                    );
 6729                    this.highlight_background::<DocumentHighlightWrite>(
 6730                        &write_ranges,
 6731                        |theme| theme.colors().editor_document_highlight_write_background,
 6732                        cx,
 6733                    );
 6734                    cx.notify();
 6735                })
 6736                .log_err();
 6737            }
 6738        }));
 6739        None
 6740    }
 6741
 6742    fn prepare_highlight_query_from_selection(
 6743        &mut self,
 6744        cx: &mut Context<Editor>,
 6745    ) -> Option<(String, Range<Anchor>)> {
 6746        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6747            return None;
 6748        }
 6749        if !EditorSettings::get_global(cx).selection_highlight {
 6750            return None;
 6751        }
 6752        if self.selections.count() != 1 || self.selections.line_mode {
 6753            return None;
 6754        }
 6755        let selection = self.selections.newest::<Point>(cx);
 6756        if selection.is_empty() || selection.start.row != selection.end.row {
 6757            return None;
 6758        }
 6759        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6760        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6761        let query = multi_buffer_snapshot
 6762            .text_for_range(selection_anchor_range.clone())
 6763            .collect::<String>();
 6764        if query.trim().is_empty() {
 6765            return None;
 6766        }
 6767        Some((query, selection_anchor_range))
 6768    }
 6769
 6770    fn update_selection_occurrence_highlights(
 6771        &mut self,
 6772        query_text: String,
 6773        query_range: Range<Anchor>,
 6774        multi_buffer_range_to_query: Range<Point>,
 6775        use_debounce: bool,
 6776        window: &mut Window,
 6777        cx: &mut Context<Editor>,
 6778    ) -> Task<()> {
 6779        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6780        cx.spawn_in(window, async move |editor, cx| {
 6781            if use_debounce {
 6782                cx.background_executor()
 6783                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6784                    .await;
 6785            }
 6786            let match_task = cx.background_spawn(async move {
 6787                let buffer_ranges = multi_buffer_snapshot
 6788                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6789                    .into_iter()
 6790                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6791                let mut match_ranges = Vec::new();
 6792                let Ok(regex) = project::search::SearchQuery::text(
 6793                    query_text.clone(),
 6794                    false,
 6795                    false,
 6796                    false,
 6797                    Default::default(),
 6798                    Default::default(),
 6799                    false,
 6800                    None,
 6801                ) else {
 6802                    return Vec::default();
 6803                };
 6804                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6805                    match_ranges.extend(
 6806                        regex
 6807                            .search(&buffer_snapshot, Some(search_range.clone()))
 6808                            .await
 6809                            .into_iter()
 6810                            .filter_map(|match_range| {
 6811                                let match_start = buffer_snapshot
 6812                                    .anchor_after(search_range.start + match_range.start);
 6813                                let match_end = buffer_snapshot
 6814                                    .anchor_before(search_range.start + match_range.end);
 6815                                let match_anchor_range = Anchor::range_in_buffer(
 6816                                    excerpt_id,
 6817                                    buffer_snapshot.remote_id(),
 6818                                    match_start..match_end,
 6819                                );
 6820                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6821                            }),
 6822                    );
 6823                }
 6824                match_ranges
 6825            });
 6826            let match_ranges = match_task.await;
 6827            editor
 6828                .update_in(cx, |editor, _, cx| {
 6829                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6830                    if !match_ranges.is_empty() {
 6831                        editor.highlight_background::<SelectedTextHighlight>(
 6832                            &match_ranges,
 6833                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6834                            cx,
 6835                        )
 6836                    }
 6837                })
 6838                .log_err();
 6839        })
 6840    }
 6841
 6842    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6843        struct NewlineFold;
 6844        let type_id = std::any::TypeId::of::<NewlineFold>();
 6845        if !self.mode.is_single_line() {
 6846            return;
 6847        }
 6848        let snapshot = self.snapshot(window, cx);
 6849        if snapshot.buffer_snapshot.max_point().row == 0 {
 6850            return;
 6851        }
 6852        let task = cx.background_spawn(async move {
 6853            let new_newlines = snapshot
 6854                .buffer_chars_at(0)
 6855                .filter_map(|(c, i)| {
 6856                    if c == '\n' {
 6857                        Some(
 6858                            snapshot.buffer_snapshot.anchor_after(i)
 6859                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6860                        )
 6861                    } else {
 6862                        None
 6863                    }
 6864                })
 6865                .collect::<Vec<_>>();
 6866            let existing_newlines = snapshot
 6867                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6868                .filter_map(|fold| {
 6869                    if fold.placeholder.type_tag == Some(type_id) {
 6870                        Some(fold.range.start..fold.range.end)
 6871                    } else {
 6872                        None
 6873                    }
 6874                })
 6875                .collect::<Vec<_>>();
 6876
 6877            (new_newlines, existing_newlines)
 6878        });
 6879        self.folding_newlines = cx.spawn(async move |this, cx| {
 6880            let (new_newlines, existing_newlines) = task.await;
 6881            if new_newlines == existing_newlines {
 6882                return;
 6883            }
 6884            let placeholder = FoldPlaceholder {
 6885                render: Arc::new(move |_, _, cx| {
 6886                    div()
 6887                        .bg(cx.theme().status().hint_background)
 6888                        .border_b_1()
 6889                        .size_full()
 6890                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6891                        .border_color(cx.theme().status().hint)
 6892                        .child("\\n")
 6893                        .into_any()
 6894                }),
 6895                constrain_width: false,
 6896                merge_adjacent: false,
 6897                type_tag: Some(type_id),
 6898            };
 6899            let creases = new_newlines
 6900                .into_iter()
 6901                .map(|range| Crease::simple(range, placeholder.clone()))
 6902                .collect();
 6903            this.update(cx, |this, cx| {
 6904                this.display_map.update(cx, |display_map, cx| {
 6905                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6906                    display_map.fold(creases, cx);
 6907                });
 6908            })
 6909            .ok();
 6910        });
 6911    }
 6912
 6913    fn refresh_selected_text_highlights(
 6914        &mut self,
 6915        on_buffer_edit: bool,
 6916        window: &mut Window,
 6917        cx: &mut Context<Editor>,
 6918    ) {
 6919        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6920        else {
 6921            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6922            self.quick_selection_highlight_task.take();
 6923            self.debounced_selection_highlight_task.take();
 6924            return;
 6925        };
 6926        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6927        if on_buffer_edit
 6928            || self
 6929                .quick_selection_highlight_task
 6930                .as_ref()
 6931                .map_or(true, |(prev_anchor_range, _)| {
 6932                    prev_anchor_range != &query_range
 6933                })
 6934        {
 6935            let multi_buffer_visible_start = self
 6936                .scroll_manager
 6937                .anchor()
 6938                .anchor
 6939                .to_point(&multi_buffer_snapshot);
 6940            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6941                multi_buffer_visible_start
 6942                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6943                Bias::Left,
 6944            );
 6945            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6946            self.quick_selection_highlight_task = Some((
 6947                query_range.clone(),
 6948                self.update_selection_occurrence_highlights(
 6949                    query_text.clone(),
 6950                    query_range.clone(),
 6951                    multi_buffer_visible_range,
 6952                    false,
 6953                    window,
 6954                    cx,
 6955                ),
 6956            ));
 6957        }
 6958        if on_buffer_edit
 6959            || self
 6960                .debounced_selection_highlight_task
 6961                .as_ref()
 6962                .map_or(true, |(prev_anchor_range, _)| {
 6963                    prev_anchor_range != &query_range
 6964                })
 6965        {
 6966            let multi_buffer_start = multi_buffer_snapshot
 6967                .anchor_before(0)
 6968                .to_point(&multi_buffer_snapshot);
 6969            let multi_buffer_end = multi_buffer_snapshot
 6970                .anchor_after(multi_buffer_snapshot.len())
 6971                .to_point(&multi_buffer_snapshot);
 6972            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6973            self.debounced_selection_highlight_task = Some((
 6974                query_range.clone(),
 6975                self.update_selection_occurrence_highlights(
 6976                    query_text,
 6977                    query_range,
 6978                    multi_buffer_full_range,
 6979                    true,
 6980                    window,
 6981                    cx,
 6982                ),
 6983            ));
 6984        }
 6985    }
 6986
 6987    pub fn refresh_inline_completion(
 6988        &mut self,
 6989        debounce: bool,
 6990        user_requested: bool,
 6991        window: &mut Window,
 6992        cx: &mut Context<Self>,
 6993    ) -> Option<()> {
 6994        let provider = self.edit_prediction_provider()?;
 6995        let cursor = self.selections.newest_anchor().head();
 6996        let (buffer, cursor_buffer_position) =
 6997            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6998
 6999        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7000            self.discard_inline_completion(false, cx);
 7001            return None;
 7002        }
 7003
 7004        if !user_requested
 7005            && (!self.should_show_edit_predictions()
 7006                || !self.is_focused(window)
 7007                || buffer.read(cx).is_empty())
 7008        {
 7009            self.discard_inline_completion(false, cx);
 7010            return None;
 7011        }
 7012
 7013        self.update_visible_inline_completion(window, cx);
 7014        provider.refresh(
 7015            self.project.clone(),
 7016            buffer,
 7017            cursor_buffer_position,
 7018            debounce,
 7019            cx,
 7020        );
 7021        Some(())
 7022    }
 7023
 7024    fn show_edit_predictions_in_menu(&self) -> bool {
 7025        match self.edit_prediction_settings {
 7026            EditPredictionSettings::Disabled => false,
 7027            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7028        }
 7029    }
 7030
 7031    pub fn edit_predictions_enabled(&self) -> bool {
 7032        match self.edit_prediction_settings {
 7033            EditPredictionSettings::Disabled => false,
 7034            EditPredictionSettings::Enabled { .. } => true,
 7035        }
 7036    }
 7037
 7038    fn edit_prediction_requires_modifier(&self) -> bool {
 7039        match self.edit_prediction_settings {
 7040            EditPredictionSettings::Disabled => false,
 7041            EditPredictionSettings::Enabled {
 7042                preview_requires_modifier,
 7043                ..
 7044            } => preview_requires_modifier,
 7045        }
 7046    }
 7047
 7048    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7049        if self.edit_prediction_provider.is_none() {
 7050            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7051        } else {
 7052            let selection = self.selections.newest_anchor();
 7053            let cursor = selection.head();
 7054
 7055            if let Some((buffer, cursor_buffer_position)) =
 7056                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7057            {
 7058                self.edit_prediction_settings =
 7059                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7060            }
 7061        }
 7062    }
 7063
 7064    fn edit_prediction_settings_at_position(
 7065        &self,
 7066        buffer: &Entity<Buffer>,
 7067        buffer_position: language::Anchor,
 7068        cx: &App,
 7069    ) -> EditPredictionSettings {
 7070        if !self.mode.is_full()
 7071            || !self.show_inline_completions_override.unwrap_or(true)
 7072            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7073        {
 7074            return EditPredictionSettings::Disabled;
 7075        }
 7076
 7077        let buffer = buffer.read(cx);
 7078
 7079        let file = buffer.file();
 7080
 7081        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7082            return EditPredictionSettings::Disabled;
 7083        };
 7084
 7085        let by_provider = matches!(
 7086            self.menu_inline_completions_policy,
 7087            MenuInlineCompletionsPolicy::ByProvider
 7088        );
 7089
 7090        let show_in_menu = by_provider
 7091            && self
 7092                .edit_prediction_provider
 7093                .as_ref()
 7094                .map_or(false, |provider| {
 7095                    provider.provider.show_completions_in_menu()
 7096                });
 7097
 7098        let preview_requires_modifier =
 7099            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7100
 7101        EditPredictionSettings::Enabled {
 7102            show_in_menu,
 7103            preview_requires_modifier,
 7104        }
 7105    }
 7106
 7107    fn should_show_edit_predictions(&self) -> bool {
 7108        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7109    }
 7110
 7111    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7112        matches!(
 7113            self.edit_prediction_preview,
 7114            EditPredictionPreview::Active { .. }
 7115        )
 7116    }
 7117
 7118    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7119        let cursor = self.selections.newest_anchor().head();
 7120        if let Some((buffer, cursor_position)) =
 7121            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7122        {
 7123            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7124        } else {
 7125            false
 7126        }
 7127    }
 7128
 7129    pub fn supports_minimap(&self, cx: &App) -> bool {
 7130        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7131    }
 7132
 7133    fn edit_predictions_enabled_in_buffer(
 7134        &self,
 7135        buffer: &Entity<Buffer>,
 7136        buffer_position: language::Anchor,
 7137        cx: &App,
 7138    ) -> bool {
 7139        maybe!({
 7140            if self.read_only(cx) {
 7141                return Some(false);
 7142            }
 7143            let provider = self.edit_prediction_provider()?;
 7144            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7145                return Some(false);
 7146            }
 7147            let buffer = buffer.read(cx);
 7148            let Some(file) = buffer.file() else {
 7149                return Some(true);
 7150            };
 7151            let settings = all_language_settings(Some(file), cx);
 7152            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7153        })
 7154        .unwrap_or(false)
 7155    }
 7156
 7157    fn cycle_inline_completion(
 7158        &mut self,
 7159        direction: Direction,
 7160        window: &mut Window,
 7161        cx: &mut Context<Self>,
 7162    ) -> Option<()> {
 7163        let provider = self.edit_prediction_provider()?;
 7164        let cursor = self.selections.newest_anchor().head();
 7165        let (buffer, cursor_buffer_position) =
 7166            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7167        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7168            return None;
 7169        }
 7170
 7171        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7172        self.update_visible_inline_completion(window, cx);
 7173
 7174        Some(())
 7175    }
 7176
 7177    pub fn show_inline_completion(
 7178        &mut self,
 7179        _: &ShowEditPrediction,
 7180        window: &mut Window,
 7181        cx: &mut Context<Self>,
 7182    ) {
 7183        if !self.has_active_inline_completion() {
 7184            self.refresh_inline_completion(false, true, window, cx);
 7185            return;
 7186        }
 7187
 7188        self.update_visible_inline_completion(window, cx);
 7189    }
 7190
 7191    pub fn display_cursor_names(
 7192        &mut self,
 7193        _: &DisplayCursorNames,
 7194        window: &mut Window,
 7195        cx: &mut Context<Self>,
 7196    ) {
 7197        self.show_cursor_names(window, cx);
 7198    }
 7199
 7200    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7201        self.show_cursor_names = true;
 7202        cx.notify();
 7203        cx.spawn_in(window, async move |this, cx| {
 7204            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7205            this.update(cx, |this, cx| {
 7206                this.show_cursor_names = false;
 7207                cx.notify()
 7208            })
 7209            .ok()
 7210        })
 7211        .detach();
 7212    }
 7213
 7214    pub fn next_edit_prediction(
 7215        &mut self,
 7216        _: &NextEditPrediction,
 7217        window: &mut Window,
 7218        cx: &mut Context<Self>,
 7219    ) {
 7220        if self.has_active_inline_completion() {
 7221            self.cycle_inline_completion(Direction::Next, window, cx);
 7222        } else {
 7223            let is_copilot_disabled = self
 7224                .refresh_inline_completion(false, true, window, cx)
 7225                .is_none();
 7226            if is_copilot_disabled {
 7227                cx.propagate();
 7228            }
 7229        }
 7230    }
 7231
 7232    pub fn previous_edit_prediction(
 7233        &mut self,
 7234        _: &PreviousEditPrediction,
 7235        window: &mut Window,
 7236        cx: &mut Context<Self>,
 7237    ) {
 7238        if self.has_active_inline_completion() {
 7239            self.cycle_inline_completion(Direction::Prev, window, cx);
 7240        } else {
 7241            let is_copilot_disabled = self
 7242                .refresh_inline_completion(false, true, window, cx)
 7243                .is_none();
 7244            if is_copilot_disabled {
 7245                cx.propagate();
 7246            }
 7247        }
 7248    }
 7249
 7250    pub fn accept_edit_prediction(
 7251        &mut self,
 7252        _: &AcceptEditPrediction,
 7253        window: &mut Window,
 7254        cx: &mut Context<Self>,
 7255    ) {
 7256        if self.show_edit_predictions_in_menu() {
 7257            self.hide_context_menu(window, cx);
 7258        }
 7259
 7260        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7261            return;
 7262        };
 7263
 7264        self.report_inline_completion_event(
 7265            active_inline_completion.completion_id.clone(),
 7266            true,
 7267            cx,
 7268        );
 7269
 7270        match &active_inline_completion.completion {
 7271            InlineCompletion::Move { target, .. } => {
 7272                let target = *target;
 7273
 7274                if let Some(position_map) = &self.last_position_map {
 7275                    if position_map
 7276                        .visible_row_range
 7277                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7278                        || !self.edit_prediction_requires_modifier()
 7279                    {
 7280                        self.unfold_ranges(&[target..target], true, false, cx);
 7281                        // Note that this is also done in vim's handler of the Tab action.
 7282                        self.change_selections(
 7283                            SelectionEffects::scroll(Autoscroll::newest()),
 7284                            window,
 7285                            cx,
 7286                            |selections| {
 7287                                selections.select_anchor_ranges([target..target]);
 7288                            },
 7289                        );
 7290                        self.clear_row_highlights::<EditPredictionPreview>();
 7291
 7292                        self.edit_prediction_preview
 7293                            .set_previous_scroll_position(None);
 7294                    } else {
 7295                        self.edit_prediction_preview
 7296                            .set_previous_scroll_position(Some(
 7297                                position_map.snapshot.scroll_anchor,
 7298                            ));
 7299
 7300                        self.highlight_rows::<EditPredictionPreview>(
 7301                            target..target,
 7302                            cx.theme().colors().editor_highlighted_line_background,
 7303                            RowHighlightOptions {
 7304                                autoscroll: true,
 7305                                ..Default::default()
 7306                            },
 7307                            cx,
 7308                        );
 7309                        self.request_autoscroll(Autoscroll::fit(), cx);
 7310                    }
 7311                }
 7312            }
 7313            InlineCompletion::Edit { edits, .. } => {
 7314                if let Some(provider) = self.edit_prediction_provider() {
 7315                    provider.accept(cx);
 7316                }
 7317
 7318                // Store the transaction ID and selections before applying the edit
 7319                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7320
 7321                let snapshot = self.buffer.read(cx).snapshot(cx);
 7322                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7323
 7324                self.buffer.update(cx, |buffer, cx| {
 7325                    buffer.edit(edits.iter().cloned(), None, cx)
 7326                });
 7327
 7328                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7329                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7330                });
 7331
 7332                let selections = self.selections.disjoint_anchors();
 7333                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7334                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7335                    if has_new_transaction {
 7336                        self.selection_history
 7337                            .insert_transaction(transaction_id_now, selections);
 7338                    }
 7339                }
 7340
 7341                self.update_visible_inline_completion(window, cx);
 7342                if self.active_inline_completion.is_none() {
 7343                    self.refresh_inline_completion(true, true, window, cx);
 7344                }
 7345
 7346                cx.notify();
 7347            }
 7348        }
 7349
 7350        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7351    }
 7352
 7353    pub fn accept_partial_inline_completion(
 7354        &mut self,
 7355        _: &AcceptPartialEditPrediction,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7360            return;
 7361        };
 7362        if self.selections.count() != 1 {
 7363            return;
 7364        }
 7365
 7366        self.report_inline_completion_event(
 7367            active_inline_completion.completion_id.clone(),
 7368            true,
 7369            cx,
 7370        );
 7371
 7372        match &active_inline_completion.completion {
 7373            InlineCompletion::Move { target, .. } => {
 7374                let target = *target;
 7375                self.change_selections(
 7376                    SelectionEffects::scroll(Autoscroll::newest()),
 7377                    window,
 7378                    cx,
 7379                    |selections| {
 7380                        selections.select_anchor_ranges([target..target]);
 7381                    },
 7382                );
 7383            }
 7384            InlineCompletion::Edit { edits, .. } => {
 7385                // Find an insertion that starts at the cursor position.
 7386                let snapshot = self.buffer.read(cx).snapshot(cx);
 7387                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7388                let insertion = edits.iter().find_map(|(range, text)| {
 7389                    let range = range.to_offset(&snapshot);
 7390                    if range.is_empty() && range.start == cursor_offset {
 7391                        Some(text)
 7392                    } else {
 7393                        None
 7394                    }
 7395                });
 7396
 7397                if let Some(text) = insertion {
 7398                    let mut partial_completion = text
 7399                        .chars()
 7400                        .by_ref()
 7401                        .take_while(|c| c.is_alphabetic())
 7402                        .collect::<String>();
 7403                    if partial_completion.is_empty() {
 7404                        partial_completion = text
 7405                            .chars()
 7406                            .by_ref()
 7407                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7408                            .collect::<String>();
 7409                    }
 7410
 7411                    cx.emit(EditorEvent::InputHandled {
 7412                        utf16_range_to_replace: None,
 7413                        text: partial_completion.clone().into(),
 7414                    });
 7415
 7416                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7417
 7418                    self.refresh_inline_completion(true, true, window, cx);
 7419                    cx.notify();
 7420                } else {
 7421                    self.accept_edit_prediction(&Default::default(), window, cx);
 7422                }
 7423            }
 7424        }
 7425    }
 7426
 7427    fn discard_inline_completion(
 7428        &mut self,
 7429        should_report_inline_completion_event: bool,
 7430        cx: &mut Context<Self>,
 7431    ) -> bool {
 7432        if should_report_inline_completion_event {
 7433            let completion_id = self
 7434                .active_inline_completion
 7435                .as_ref()
 7436                .and_then(|active_completion| active_completion.completion_id.clone());
 7437
 7438            self.report_inline_completion_event(completion_id, false, cx);
 7439        }
 7440
 7441        if let Some(provider) = self.edit_prediction_provider() {
 7442            provider.discard(cx);
 7443        }
 7444
 7445        self.take_active_inline_completion(cx)
 7446    }
 7447
 7448    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7449        let Some(provider) = self.edit_prediction_provider() else {
 7450            return;
 7451        };
 7452
 7453        let Some((_, buffer, _)) = self
 7454            .buffer
 7455            .read(cx)
 7456            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7457        else {
 7458            return;
 7459        };
 7460
 7461        let extension = buffer
 7462            .read(cx)
 7463            .file()
 7464            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7465
 7466        let event_type = match accepted {
 7467            true => "Edit Prediction Accepted",
 7468            false => "Edit Prediction Discarded",
 7469        };
 7470        telemetry::event!(
 7471            event_type,
 7472            provider = provider.name(),
 7473            prediction_id = id,
 7474            suggestion_accepted = accepted,
 7475            file_extension = extension,
 7476        );
 7477    }
 7478
 7479    pub fn has_active_inline_completion(&self) -> bool {
 7480        self.active_inline_completion.is_some()
 7481    }
 7482
 7483    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7484        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7485            return false;
 7486        };
 7487
 7488        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7489        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7490        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7491        true
 7492    }
 7493
 7494    /// Returns true when we're displaying the edit prediction popover below the cursor
 7495    /// like we are not previewing and the LSP autocomplete menu is visible
 7496    /// or we are in `when_holding_modifier` mode.
 7497    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7498        if self.edit_prediction_preview_is_active()
 7499            || !self.show_edit_predictions_in_menu()
 7500            || !self.edit_predictions_enabled()
 7501        {
 7502            return false;
 7503        }
 7504
 7505        if self.has_visible_completions_menu() {
 7506            return true;
 7507        }
 7508
 7509        has_completion && self.edit_prediction_requires_modifier()
 7510    }
 7511
 7512    fn handle_modifiers_changed(
 7513        &mut self,
 7514        modifiers: Modifiers,
 7515        position_map: &PositionMap,
 7516        window: &mut Window,
 7517        cx: &mut Context<Self>,
 7518    ) {
 7519        if self.show_edit_predictions_in_menu() {
 7520            self.update_edit_prediction_preview(&modifiers, window, cx);
 7521        }
 7522
 7523        self.update_selection_mode(&modifiers, position_map, window, cx);
 7524
 7525        let mouse_position = window.mouse_position();
 7526        if !position_map.text_hitbox.is_hovered(window) {
 7527            return;
 7528        }
 7529
 7530        self.update_hovered_link(
 7531            position_map.point_for_position(mouse_position),
 7532            &position_map.snapshot,
 7533            modifiers,
 7534            window,
 7535            cx,
 7536        )
 7537    }
 7538
 7539    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7540        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7541        if invert {
 7542            match multi_cursor_setting {
 7543                MultiCursorModifier::Alt => modifiers.alt,
 7544                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7545            }
 7546        } else {
 7547            match multi_cursor_setting {
 7548                MultiCursorModifier::Alt => modifiers.secondary(),
 7549                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7550            }
 7551        }
 7552    }
 7553
 7554    fn columnar_selection_mode(
 7555        modifiers: &Modifiers,
 7556        cx: &mut Context<Self>,
 7557    ) -> Option<ColumnarMode> {
 7558        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7559            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7560                Some(ColumnarMode::FromMouse)
 7561            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7562                Some(ColumnarMode::FromSelection)
 7563            } else {
 7564                None
 7565            }
 7566        } else {
 7567            None
 7568        }
 7569    }
 7570
 7571    fn update_selection_mode(
 7572        &mut self,
 7573        modifiers: &Modifiers,
 7574        position_map: &PositionMap,
 7575        window: &mut Window,
 7576        cx: &mut Context<Self>,
 7577    ) {
 7578        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7579            return;
 7580        };
 7581        if self.selections.pending.is_none() {
 7582            return;
 7583        }
 7584
 7585        let mouse_position = window.mouse_position();
 7586        let point_for_position = position_map.point_for_position(mouse_position);
 7587        let position = point_for_position.previous_valid;
 7588
 7589        self.select(
 7590            SelectPhase::BeginColumnar {
 7591                position,
 7592                reset: false,
 7593                mode,
 7594                goal_column: point_for_position.exact_unclipped.column(),
 7595            },
 7596            window,
 7597            cx,
 7598        );
 7599    }
 7600
 7601    fn update_edit_prediction_preview(
 7602        &mut self,
 7603        modifiers: &Modifiers,
 7604        window: &mut Window,
 7605        cx: &mut Context<Self>,
 7606    ) {
 7607        let mut modifiers_held = false;
 7608        if let Some(accept_keystroke) = self
 7609            .accept_edit_prediction_keybind(false, window, cx)
 7610            .keystroke()
 7611        {
 7612            modifiers_held = modifiers_held
 7613                || (&accept_keystroke.modifiers == modifiers
 7614                    && accept_keystroke.modifiers.modified());
 7615        };
 7616        if let Some(accept_partial_keystroke) = self
 7617            .accept_edit_prediction_keybind(true, window, cx)
 7618            .keystroke()
 7619        {
 7620            modifiers_held = modifiers_held
 7621                || (&accept_partial_keystroke.modifiers == modifiers
 7622                    && accept_partial_keystroke.modifiers.modified());
 7623        }
 7624
 7625        if modifiers_held {
 7626            if matches!(
 7627                self.edit_prediction_preview,
 7628                EditPredictionPreview::Inactive { .. }
 7629            ) {
 7630                self.edit_prediction_preview = EditPredictionPreview::Active {
 7631                    previous_scroll_position: None,
 7632                    since: Instant::now(),
 7633                };
 7634
 7635                self.update_visible_inline_completion(window, cx);
 7636                cx.notify();
 7637            }
 7638        } else if let EditPredictionPreview::Active {
 7639            previous_scroll_position,
 7640            since,
 7641        } = self.edit_prediction_preview
 7642        {
 7643            if let (Some(previous_scroll_position), Some(position_map)) =
 7644                (previous_scroll_position, self.last_position_map.as_ref())
 7645            {
 7646                self.set_scroll_position(
 7647                    previous_scroll_position
 7648                        .scroll_position(&position_map.snapshot.display_snapshot),
 7649                    window,
 7650                    cx,
 7651                );
 7652            }
 7653
 7654            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7655                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7656            };
 7657            self.clear_row_highlights::<EditPredictionPreview>();
 7658            self.update_visible_inline_completion(window, cx);
 7659            cx.notify();
 7660        }
 7661    }
 7662
 7663    fn update_visible_inline_completion(
 7664        &mut self,
 7665        _window: &mut Window,
 7666        cx: &mut Context<Self>,
 7667    ) -> Option<()> {
 7668        let selection = self.selections.newest_anchor();
 7669        let cursor = selection.head();
 7670        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7671        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7672        let excerpt_id = cursor.excerpt_id;
 7673
 7674        let show_in_menu = self.show_edit_predictions_in_menu();
 7675        let completions_menu_has_precedence = !show_in_menu
 7676            && (self.context_menu.borrow().is_some()
 7677                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7678
 7679        if completions_menu_has_precedence
 7680            || !offset_selection.is_empty()
 7681            || self
 7682                .active_inline_completion
 7683                .as_ref()
 7684                .map_or(false, |completion| {
 7685                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7686                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7687                    !invalidation_range.contains(&offset_selection.head())
 7688                })
 7689        {
 7690            self.discard_inline_completion(false, cx);
 7691            return None;
 7692        }
 7693
 7694        self.take_active_inline_completion(cx);
 7695        let Some(provider) = self.edit_prediction_provider() else {
 7696            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7697            return None;
 7698        };
 7699
 7700        let (buffer, cursor_buffer_position) =
 7701            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7702
 7703        self.edit_prediction_settings =
 7704            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7705
 7706        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7707
 7708        if self.edit_prediction_indent_conflict {
 7709            let cursor_point = cursor.to_point(&multibuffer);
 7710
 7711            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7712
 7713            if let Some((_, indent)) = indents.iter().next() {
 7714                if indent.len == cursor_point.column {
 7715                    self.edit_prediction_indent_conflict = false;
 7716                }
 7717            }
 7718        }
 7719
 7720        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7721        let edits = inline_completion
 7722            .edits
 7723            .into_iter()
 7724            .flat_map(|(range, new_text)| {
 7725                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7726                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7727                Some((start..end, new_text))
 7728            })
 7729            .collect::<Vec<_>>();
 7730        if edits.is_empty() {
 7731            return None;
 7732        }
 7733
 7734        let first_edit_start = edits.first().unwrap().0.start;
 7735        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7736        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7737
 7738        let last_edit_end = edits.last().unwrap().0.end;
 7739        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7740        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7741
 7742        let cursor_row = cursor.to_point(&multibuffer).row;
 7743
 7744        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7745
 7746        let mut inlay_ids = Vec::new();
 7747        let invalidation_row_range;
 7748        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7749            Some(cursor_row..edit_end_row)
 7750        } else if cursor_row > edit_end_row {
 7751            Some(edit_start_row..cursor_row)
 7752        } else {
 7753            None
 7754        };
 7755        let is_move =
 7756            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7757        let completion = if is_move {
 7758            invalidation_row_range =
 7759                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7760            let target = first_edit_start;
 7761            InlineCompletion::Move { target, snapshot }
 7762        } else {
 7763            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7764                && !self.inline_completions_hidden_for_vim_mode;
 7765
 7766            if show_completions_in_buffer {
 7767                if edits
 7768                    .iter()
 7769                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7770                {
 7771                    let mut inlays = Vec::new();
 7772                    for (range, new_text) in &edits {
 7773                        let inlay = Inlay::inline_completion(
 7774                            post_inc(&mut self.next_inlay_id),
 7775                            range.start,
 7776                            new_text.as_str(),
 7777                        );
 7778                        inlay_ids.push(inlay.id);
 7779                        inlays.push(inlay);
 7780                    }
 7781
 7782                    self.splice_inlays(&[], inlays, cx);
 7783                } else {
 7784                    let background_color = cx.theme().status().deleted_background;
 7785                    self.highlight_text::<InlineCompletionHighlight>(
 7786                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7787                        HighlightStyle {
 7788                            background_color: Some(background_color),
 7789                            ..Default::default()
 7790                        },
 7791                        cx,
 7792                    );
 7793                }
 7794            }
 7795
 7796            invalidation_row_range = edit_start_row..edit_end_row;
 7797
 7798            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7799                if provider.show_tab_accept_marker() {
 7800                    EditDisplayMode::TabAccept
 7801                } else {
 7802                    EditDisplayMode::Inline
 7803                }
 7804            } else {
 7805                EditDisplayMode::DiffPopover
 7806            };
 7807
 7808            InlineCompletion::Edit {
 7809                edits,
 7810                edit_preview: inline_completion.edit_preview,
 7811                display_mode,
 7812                snapshot,
 7813            }
 7814        };
 7815
 7816        let invalidation_range = multibuffer
 7817            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7818            ..multibuffer.anchor_after(Point::new(
 7819                invalidation_row_range.end,
 7820                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7821            ));
 7822
 7823        self.stale_inline_completion_in_menu = None;
 7824        self.active_inline_completion = Some(InlineCompletionState {
 7825            inlay_ids,
 7826            completion,
 7827            completion_id: inline_completion.id,
 7828            invalidation_range,
 7829        });
 7830
 7831        cx.notify();
 7832
 7833        Some(())
 7834    }
 7835
 7836    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7837        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7838    }
 7839
 7840    fn clear_tasks(&mut self) {
 7841        self.tasks.clear()
 7842    }
 7843
 7844    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7845        if self.tasks.insert(key, value).is_some() {
 7846            // This case should hopefully be rare, but just in case...
 7847            log::error!(
 7848                "multiple different run targets found on a single line, only the last target will be rendered"
 7849            )
 7850        }
 7851    }
 7852
 7853    /// Get all display points of breakpoints that will be rendered within editor
 7854    ///
 7855    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7856    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7857    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7858    fn active_breakpoints(
 7859        &self,
 7860        range: Range<DisplayRow>,
 7861        window: &mut Window,
 7862        cx: &mut Context<Self>,
 7863    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7864        let mut breakpoint_display_points = HashMap::default();
 7865
 7866        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7867            return breakpoint_display_points;
 7868        };
 7869
 7870        let snapshot = self.snapshot(window, cx);
 7871
 7872        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7873        let Some(project) = self.project.as_ref() else {
 7874            return breakpoint_display_points;
 7875        };
 7876
 7877        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7878            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7879
 7880        for (buffer_snapshot, range, excerpt_id) in
 7881            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7882        {
 7883            let Some(buffer) = project
 7884                .read(cx)
 7885                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7886            else {
 7887                continue;
 7888            };
 7889            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7890                &buffer,
 7891                Some(
 7892                    buffer_snapshot.anchor_before(range.start)
 7893                        ..buffer_snapshot.anchor_after(range.end),
 7894                ),
 7895                buffer_snapshot,
 7896                cx,
 7897            );
 7898            for (breakpoint, state) in breakpoints {
 7899                let multi_buffer_anchor =
 7900                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7901                let position = multi_buffer_anchor
 7902                    .to_point(&multi_buffer_snapshot)
 7903                    .to_display_point(&snapshot);
 7904
 7905                breakpoint_display_points.insert(
 7906                    position.row(),
 7907                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7908                );
 7909            }
 7910        }
 7911
 7912        breakpoint_display_points
 7913    }
 7914
 7915    fn breakpoint_context_menu(
 7916        &self,
 7917        anchor: Anchor,
 7918        window: &mut Window,
 7919        cx: &mut Context<Self>,
 7920    ) -> Entity<ui::ContextMenu> {
 7921        let weak_editor = cx.weak_entity();
 7922        let focus_handle = self.focus_handle(cx);
 7923
 7924        let row = self
 7925            .buffer
 7926            .read(cx)
 7927            .snapshot(cx)
 7928            .summary_for_anchor::<Point>(&anchor)
 7929            .row;
 7930
 7931        let breakpoint = self
 7932            .breakpoint_at_row(row, window, cx)
 7933            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7934
 7935        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7936            "Edit Log Breakpoint"
 7937        } else {
 7938            "Set Log Breakpoint"
 7939        };
 7940
 7941        let condition_breakpoint_msg = if breakpoint
 7942            .as_ref()
 7943            .is_some_and(|bp| bp.1.condition.is_some())
 7944        {
 7945            "Edit Condition Breakpoint"
 7946        } else {
 7947            "Set Condition Breakpoint"
 7948        };
 7949
 7950        let hit_condition_breakpoint_msg = if breakpoint
 7951            .as_ref()
 7952            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7953        {
 7954            "Edit Hit Condition Breakpoint"
 7955        } else {
 7956            "Set Hit Condition Breakpoint"
 7957        };
 7958
 7959        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7960            "Unset Breakpoint"
 7961        } else {
 7962            "Set Breakpoint"
 7963        };
 7964
 7965        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7966
 7967        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7968            BreakpointState::Enabled => Some("Disable"),
 7969            BreakpointState::Disabled => Some("Enable"),
 7970        });
 7971
 7972        let (anchor, breakpoint) =
 7973            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7974
 7975        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7976            menu.on_blur_subscription(Subscription::new(|| {}))
 7977                .context(focus_handle)
 7978                .when(run_to_cursor, |this| {
 7979                    let weak_editor = weak_editor.clone();
 7980                    this.entry("Run to cursor", None, move |window, cx| {
 7981                        weak_editor
 7982                            .update(cx, |editor, cx| {
 7983                                editor.change_selections(
 7984                                    SelectionEffects::no_scroll(),
 7985                                    window,
 7986                                    cx,
 7987                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7988                                );
 7989                            })
 7990                            .ok();
 7991
 7992                        window.dispatch_action(Box::new(RunToCursor), cx);
 7993                    })
 7994                    .separator()
 7995                })
 7996                .when_some(toggle_state_msg, |this, msg| {
 7997                    this.entry(msg, None, {
 7998                        let weak_editor = weak_editor.clone();
 7999                        let breakpoint = breakpoint.clone();
 8000                        move |_window, cx| {
 8001                            weak_editor
 8002                                .update(cx, |this, cx| {
 8003                                    this.edit_breakpoint_at_anchor(
 8004                                        anchor,
 8005                                        breakpoint.as_ref().clone(),
 8006                                        BreakpointEditAction::InvertState,
 8007                                        cx,
 8008                                    );
 8009                                })
 8010                                .log_err();
 8011                        }
 8012                    })
 8013                })
 8014                .entry(set_breakpoint_msg, None, {
 8015                    let weak_editor = weak_editor.clone();
 8016                    let breakpoint = breakpoint.clone();
 8017                    move |_window, cx| {
 8018                        weak_editor
 8019                            .update(cx, |this, cx| {
 8020                                this.edit_breakpoint_at_anchor(
 8021                                    anchor,
 8022                                    breakpoint.as_ref().clone(),
 8023                                    BreakpointEditAction::Toggle,
 8024                                    cx,
 8025                                );
 8026                            })
 8027                            .log_err();
 8028                    }
 8029                })
 8030                .entry(log_breakpoint_msg, None, {
 8031                    let breakpoint = breakpoint.clone();
 8032                    let weak_editor = weak_editor.clone();
 8033                    move |window, cx| {
 8034                        weak_editor
 8035                            .update(cx, |this, cx| {
 8036                                this.add_edit_breakpoint_block(
 8037                                    anchor,
 8038                                    breakpoint.as_ref(),
 8039                                    BreakpointPromptEditAction::Log,
 8040                                    window,
 8041                                    cx,
 8042                                );
 8043                            })
 8044                            .log_err();
 8045                    }
 8046                })
 8047                .entry(condition_breakpoint_msg, None, {
 8048                    let breakpoint = breakpoint.clone();
 8049                    let weak_editor = weak_editor.clone();
 8050                    move |window, cx| {
 8051                        weak_editor
 8052                            .update(cx, |this, cx| {
 8053                                this.add_edit_breakpoint_block(
 8054                                    anchor,
 8055                                    breakpoint.as_ref(),
 8056                                    BreakpointPromptEditAction::Condition,
 8057                                    window,
 8058                                    cx,
 8059                                );
 8060                            })
 8061                            .log_err();
 8062                    }
 8063                })
 8064                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8065                    weak_editor
 8066                        .update(cx, |this, cx| {
 8067                            this.add_edit_breakpoint_block(
 8068                                anchor,
 8069                                breakpoint.as_ref(),
 8070                                BreakpointPromptEditAction::HitCondition,
 8071                                window,
 8072                                cx,
 8073                            );
 8074                        })
 8075                        .log_err();
 8076                })
 8077        })
 8078    }
 8079
 8080    fn render_breakpoint(
 8081        &self,
 8082        position: Anchor,
 8083        row: DisplayRow,
 8084        breakpoint: &Breakpoint,
 8085        state: Option<BreakpointSessionState>,
 8086        cx: &mut Context<Self>,
 8087    ) -> IconButton {
 8088        let is_rejected = state.is_some_and(|s| !s.verified);
 8089        // Is it a breakpoint that shows up when hovering over gutter?
 8090        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8091            (false, false),
 8092            |PhantomBreakpointIndicator {
 8093                 is_active,
 8094                 display_row,
 8095                 collides_with_existing_breakpoint,
 8096             }| {
 8097                (
 8098                    is_active && display_row == row,
 8099                    collides_with_existing_breakpoint,
 8100                )
 8101            },
 8102        );
 8103
 8104        let (color, icon) = {
 8105            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8106                (false, false) => ui::IconName::DebugBreakpoint,
 8107                (true, false) => ui::IconName::DebugLogBreakpoint,
 8108                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8109                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8110            };
 8111
 8112            let color = if is_phantom {
 8113                Color::Hint
 8114            } else if is_rejected {
 8115                Color::Disabled
 8116            } else {
 8117                Color::Debugger
 8118            };
 8119
 8120            (color, icon)
 8121        };
 8122
 8123        let breakpoint = Arc::from(breakpoint.clone());
 8124
 8125        let alt_as_text = gpui::Keystroke {
 8126            modifiers: Modifiers::secondary_key(),
 8127            ..Default::default()
 8128        };
 8129        let primary_action_text = if breakpoint.is_disabled() {
 8130            "Enable breakpoint"
 8131        } else if is_phantom && !collides_with_existing {
 8132            "Set breakpoint"
 8133        } else {
 8134            "Unset breakpoint"
 8135        };
 8136        let focus_handle = self.focus_handle.clone();
 8137
 8138        let meta = if is_rejected {
 8139            SharedString::from("No executable code is associated with this line.")
 8140        } else if collides_with_existing && !breakpoint.is_disabled() {
 8141            SharedString::from(format!(
 8142                "{alt_as_text}-click to disable,\nright-click for more options."
 8143            ))
 8144        } else {
 8145            SharedString::from("Right-click for more options.")
 8146        };
 8147        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8148            .icon_size(IconSize::XSmall)
 8149            .size(ui::ButtonSize::None)
 8150            .when(is_rejected, |this| {
 8151                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8152            })
 8153            .icon_color(color)
 8154            .style(ButtonStyle::Transparent)
 8155            .on_click(cx.listener({
 8156                let breakpoint = breakpoint.clone();
 8157
 8158                move |editor, event: &ClickEvent, window, cx| {
 8159                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8160                        BreakpointEditAction::InvertState
 8161                    } else {
 8162                        BreakpointEditAction::Toggle
 8163                    };
 8164
 8165                    window.focus(&editor.focus_handle(cx));
 8166                    editor.edit_breakpoint_at_anchor(
 8167                        position,
 8168                        breakpoint.as_ref().clone(),
 8169                        edit_action,
 8170                        cx,
 8171                    );
 8172                }
 8173            }))
 8174            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8175                editor.set_breakpoint_context_menu(
 8176                    row,
 8177                    Some(position),
 8178                    event.down.position,
 8179                    window,
 8180                    cx,
 8181                );
 8182            }))
 8183            .tooltip(move |window, cx| {
 8184                Tooltip::with_meta_in(
 8185                    primary_action_text,
 8186                    Some(&ToggleBreakpoint),
 8187                    meta.clone(),
 8188                    &focus_handle,
 8189                    window,
 8190                    cx,
 8191                )
 8192            })
 8193    }
 8194
 8195    fn build_tasks_context(
 8196        project: &Entity<Project>,
 8197        buffer: &Entity<Buffer>,
 8198        buffer_row: u32,
 8199        tasks: &Arc<RunnableTasks>,
 8200        cx: &mut Context<Self>,
 8201    ) -> Task<Option<task::TaskContext>> {
 8202        let position = Point::new(buffer_row, tasks.column);
 8203        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8204        let location = Location {
 8205            buffer: buffer.clone(),
 8206            range: range_start..range_start,
 8207        };
 8208        // Fill in the environmental variables from the tree-sitter captures
 8209        let mut captured_task_variables = TaskVariables::default();
 8210        for (capture_name, value) in tasks.extra_variables.clone() {
 8211            captured_task_variables.insert(
 8212                task::VariableName::Custom(capture_name.into()),
 8213                value.clone(),
 8214            );
 8215        }
 8216        project.update(cx, |project, cx| {
 8217            project.task_store().update(cx, |task_store, cx| {
 8218                task_store.task_context_for_location(captured_task_variables, location, cx)
 8219            })
 8220        })
 8221    }
 8222
 8223    pub fn spawn_nearest_task(
 8224        &mut self,
 8225        action: &SpawnNearestTask,
 8226        window: &mut Window,
 8227        cx: &mut Context<Self>,
 8228    ) {
 8229        let Some((workspace, _)) = self.workspace.clone() else {
 8230            return;
 8231        };
 8232        let Some(project) = self.project.clone() else {
 8233            return;
 8234        };
 8235
 8236        // Try to find a closest, enclosing node using tree-sitter that has a
 8237        // task
 8238        let Some((buffer, buffer_row, tasks)) = self
 8239            .find_enclosing_node_task(cx)
 8240            // Or find the task that's closest in row-distance.
 8241            .or_else(|| self.find_closest_task(cx))
 8242        else {
 8243            return;
 8244        };
 8245
 8246        let reveal_strategy = action.reveal;
 8247        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8248        cx.spawn_in(window, async move |_, cx| {
 8249            let context = task_context.await?;
 8250            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8251
 8252            let resolved = &mut resolved_task.resolved;
 8253            resolved.reveal = reveal_strategy;
 8254
 8255            workspace
 8256                .update_in(cx, |workspace, window, cx| {
 8257                    workspace.schedule_resolved_task(
 8258                        task_source_kind,
 8259                        resolved_task,
 8260                        false,
 8261                        window,
 8262                        cx,
 8263                    );
 8264                })
 8265                .ok()
 8266        })
 8267        .detach();
 8268    }
 8269
 8270    fn find_closest_task(
 8271        &mut self,
 8272        cx: &mut Context<Self>,
 8273    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8274        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8275
 8276        let ((buffer_id, row), tasks) = self
 8277            .tasks
 8278            .iter()
 8279            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8280
 8281        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8282        let tasks = Arc::new(tasks.to_owned());
 8283        Some((buffer, *row, tasks))
 8284    }
 8285
 8286    fn find_enclosing_node_task(
 8287        &mut self,
 8288        cx: &mut Context<Self>,
 8289    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8290        let snapshot = self.buffer.read(cx).snapshot(cx);
 8291        let offset = self.selections.newest::<usize>(cx).head();
 8292        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8293        let buffer_id = excerpt.buffer().remote_id();
 8294
 8295        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8296        let mut cursor = layer.node().walk();
 8297
 8298        while cursor.goto_first_child_for_byte(offset).is_some() {
 8299            if cursor.node().end_byte() == offset {
 8300                cursor.goto_next_sibling();
 8301            }
 8302        }
 8303
 8304        // Ascend to the smallest ancestor that contains the range and has a task.
 8305        loop {
 8306            let node = cursor.node();
 8307            let node_range = node.byte_range();
 8308            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8309
 8310            // Check if this node contains our offset
 8311            if node_range.start <= offset && node_range.end >= offset {
 8312                // If it contains offset, check for task
 8313                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8314                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8315                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8316                }
 8317            }
 8318
 8319            if !cursor.goto_parent() {
 8320                break;
 8321            }
 8322        }
 8323        None
 8324    }
 8325
 8326    fn render_run_indicator(
 8327        &self,
 8328        _style: &EditorStyle,
 8329        is_active: bool,
 8330        row: DisplayRow,
 8331        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8332        cx: &mut Context<Self>,
 8333    ) -> IconButton {
 8334        let color = Color::Muted;
 8335        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8336
 8337        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8338            .shape(ui::IconButtonShape::Square)
 8339            .icon_size(IconSize::XSmall)
 8340            .icon_color(color)
 8341            .toggle_state(is_active)
 8342            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8343                let quick_launch = e.down.button == MouseButton::Left;
 8344                window.focus(&editor.focus_handle(cx));
 8345                editor.toggle_code_actions(
 8346                    &ToggleCodeActions {
 8347                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8348                        quick_launch,
 8349                    },
 8350                    window,
 8351                    cx,
 8352                );
 8353            }))
 8354            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8355                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8356            }))
 8357    }
 8358
 8359    pub fn context_menu_visible(&self) -> bool {
 8360        !self.edit_prediction_preview_is_active()
 8361            && self
 8362                .context_menu
 8363                .borrow()
 8364                .as_ref()
 8365                .map_or(false, |menu| menu.visible())
 8366    }
 8367
 8368    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8369        self.context_menu
 8370            .borrow()
 8371            .as_ref()
 8372            .map(|menu| menu.origin())
 8373    }
 8374
 8375    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8376        self.context_menu_options = Some(options);
 8377    }
 8378
 8379    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8380    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8381
 8382    fn render_edit_prediction_popover(
 8383        &mut self,
 8384        text_bounds: &Bounds<Pixels>,
 8385        content_origin: gpui::Point<Pixels>,
 8386        right_margin: Pixels,
 8387        editor_snapshot: &EditorSnapshot,
 8388        visible_row_range: Range<DisplayRow>,
 8389        scroll_top: f32,
 8390        scroll_bottom: f32,
 8391        line_layouts: &[LineWithInvisibles],
 8392        line_height: Pixels,
 8393        scroll_pixel_position: gpui::Point<Pixels>,
 8394        newest_selection_head: Option<DisplayPoint>,
 8395        editor_width: Pixels,
 8396        style: &EditorStyle,
 8397        window: &mut Window,
 8398        cx: &mut App,
 8399    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8400        if self.mode().is_minimap() {
 8401            return None;
 8402        }
 8403        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8404
 8405        if self.edit_prediction_visible_in_cursor_popover(true) {
 8406            return None;
 8407        }
 8408
 8409        match &active_inline_completion.completion {
 8410            InlineCompletion::Move { target, .. } => {
 8411                let target_display_point = target.to_display_point(editor_snapshot);
 8412
 8413                if self.edit_prediction_requires_modifier() {
 8414                    if !self.edit_prediction_preview_is_active() {
 8415                        return None;
 8416                    }
 8417
 8418                    self.render_edit_prediction_modifier_jump_popover(
 8419                        text_bounds,
 8420                        content_origin,
 8421                        visible_row_range,
 8422                        line_layouts,
 8423                        line_height,
 8424                        scroll_pixel_position,
 8425                        newest_selection_head,
 8426                        target_display_point,
 8427                        window,
 8428                        cx,
 8429                    )
 8430                } else {
 8431                    self.render_edit_prediction_eager_jump_popover(
 8432                        text_bounds,
 8433                        content_origin,
 8434                        editor_snapshot,
 8435                        visible_row_range,
 8436                        scroll_top,
 8437                        scroll_bottom,
 8438                        line_height,
 8439                        scroll_pixel_position,
 8440                        target_display_point,
 8441                        editor_width,
 8442                        window,
 8443                        cx,
 8444                    )
 8445                }
 8446            }
 8447            InlineCompletion::Edit {
 8448                display_mode: EditDisplayMode::Inline,
 8449                ..
 8450            } => None,
 8451            InlineCompletion::Edit {
 8452                display_mode: EditDisplayMode::TabAccept,
 8453                edits,
 8454                ..
 8455            } => {
 8456                let range = &edits.first()?.0;
 8457                let target_display_point = range.end.to_display_point(editor_snapshot);
 8458
 8459                self.render_edit_prediction_end_of_line_popover(
 8460                    "Accept",
 8461                    editor_snapshot,
 8462                    visible_row_range,
 8463                    target_display_point,
 8464                    line_height,
 8465                    scroll_pixel_position,
 8466                    content_origin,
 8467                    editor_width,
 8468                    window,
 8469                    cx,
 8470                )
 8471            }
 8472            InlineCompletion::Edit {
 8473                edits,
 8474                edit_preview,
 8475                display_mode: EditDisplayMode::DiffPopover,
 8476                snapshot,
 8477            } => self.render_edit_prediction_diff_popover(
 8478                text_bounds,
 8479                content_origin,
 8480                right_margin,
 8481                editor_snapshot,
 8482                visible_row_range,
 8483                line_layouts,
 8484                line_height,
 8485                scroll_pixel_position,
 8486                newest_selection_head,
 8487                editor_width,
 8488                style,
 8489                edits,
 8490                edit_preview,
 8491                snapshot,
 8492                window,
 8493                cx,
 8494            ),
 8495        }
 8496    }
 8497
 8498    fn render_edit_prediction_modifier_jump_popover(
 8499        &mut self,
 8500        text_bounds: &Bounds<Pixels>,
 8501        content_origin: gpui::Point<Pixels>,
 8502        visible_row_range: Range<DisplayRow>,
 8503        line_layouts: &[LineWithInvisibles],
 8504        line_height: Pixels,
 8505        scroll_pixel_position: gpui::Point<Pixels>,
 8506        newest_selection_head: Option<DisplayPoint>,
 8507        target_display_point: DisplayPoint,
 8508        window: &mut Window,
 8509        cx: &mut App,
 8510    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8511        let scrolled_content_origin =
 8512            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8513
 8514        const SCROLL_PADDING_Y: Pixels = px(12.);
 8515
 8516        if target_display_point.row() < visible_row_range.start {
 8517            return self.render_edit_prediction_scroll_popover(
 8518                |_| SCROLL_PADDING_Y,
 8519                IconName::ArrowUp,
 8520                visible_row_range,
 8521                line_layouts,
 8522                newest_selection_head,
 8523                scrolled_content_origin,
 8524                window,
 8525                cx,
 8526            );
 8527        } else if target_display_point.row() >= visible_row_range.end {
 8528            return self.render_edit_prediction_scroll_popover(
 8529                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8530                IconName::ArrowDown,
 8531                visible_row_range,
 8532                line_layouts,
 8533                newest_selection_head,
 8534                scrolled_content_origin,
 8535                window,
 8536                cx,
 8537            );
 8538        }
 8539
 8540        const POLE_WIDTH: Pixels = px(2.);
 8541
 8542        let line_layout =
 8543            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8544        let target_column = target_display_point.column() as usize;
 8545
 8546        let target_x = line_layout.x_for_index(target_column);
 8547        let target_y =
 8548            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8549
 8550        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8551
 8552        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8553        border_color.l += 0.001;
 8554
 8555        let mut element = v_flex()
 8556            .items_end()
 8557            .when(flag_on_right, |el| el.items_start())
 8558            .child(if flag_on_right {
 8559                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8560                    .rounded_bl(px(0.))
 8561                    .rounded_tl(px(0.))
 8562                    .border_l_2()
 8563                    .border_color(border_color)
 8564            } else {
 8565                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8566                    .rounded_br(px(0.))
 8567                    .rounded_tr(px(0.))
 8568                    .border_r_2()
 8569                    .border_color(border_color)
 8570            })
 8571            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8572            .into_any();
 8573
 8574        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8575
 8576        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8577            - point(
 8578                if flag_on_right {
 8579                    POLE_WIDTH
 8580                } else {
 8581                    size.width - POLE_WIDTH
 8582                },
 8583                size.height - line_height,
 8584            );
 8585
 8586        origin.x = origin.x.max(content_origin.x);
 8587
 8588        element.prepaint_at(origin, window, cx);
 8589
 8590        Some((element, origin))
 8591    }
 8592
 8593    fn render_edit_prediction_scroll_popover(
 8594        &mut self,
 8595        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8596        scroll_icon: IconName,
 8597        visible_row_range: Range<DisplayRow>,
 8598        line_layouts: &[LineWithInvisibles],
 8599        newest_selection_head: Option<DisplayPoint>,
 8600        scrolled_content_origin: gpui::Point<Pixels>,
 8601        window: &mut Window,
 8602        cx: &mut App,
 8603    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8604        let mut element = self
 8605            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8606            .into_any();
 8607
 8608        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8609
 8610        let cursor = newest_selection_head?;
 8611        let cursor_row_layout =
 8612            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8613        let cursor_column = cursor.column() as usize;
 8614
 8615        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8616
 8617        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8618
 8619        element.prepaint_at(origin, window, cx);
 8620        Some((element, origin))
 8621    }
 8622
 8623    fn render_edit_prediction_eager_jump_popover(
 8624        &mut self,
 8625        text_bounds: &Bounds<Pixels>,
 8626        content_origin: gpui::Point<Pixels>,
 8627        editor_snapshot: &EditorSnapshot,
 8628        visible_row_range: Range<DisplayRow>,
 8629        scroll_top: f32,
 8630        scroll_bottom: f32,
 8631        line_height: Pixels,
 8632        scroll_pixel_position: gpui::Point<Pixels>,
 8633        target_display_point: DisplayPoint,
 8634        editor_width: Pixels,
 8635        window: &mut Window,
 8636        cx: &mut App,
 8637    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8638        if target_display_point.row().as_f32() < scroll_top {
 8639            let mut element = self
 8640                .render_edit_prediction_line_popover(
 8641                    "Jump to Edit",
 8642                    Some(IconName::ArrowUp),
 8643                    window,
 8644                    cx,
 8645                )?
 8646                .into_any();
 8647
 8648            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8649            let offset = point(
 8650                (text_bounds.size.width - size.width) / 2.,
 8651                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8652            );
 8653
 8654            let origin = text_bounds.origin + offset;
 8655            element.prepaint_at(origin, window, cx);
 8656            Some((element, origin))
 8657        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8658            let mut element = self
 8659                .render_edit_prediction_line_popover(
 8660                    "Jump to Edit",
 8661                    Some(IconName::ArrowDown),
 8662                    window,
 8663                    cx,
 8664                )?
 8665                .into_any();
 8666
 8667            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8668            let offset = point(
 8669                (text_bounds.size.width - size.width) / 2.,
 8670                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8671            );
 8672
 8673            let origin = text_bounds.origin + offset;
 8674            element.prepaint_at(origin, window, cx);
 8675            Some((element, origin))
 8676        } else {
 8677            self.render_edit_prediction_end_of_line_popover(
 8678                "Jump to Edit",
 8679                editor_snapshot,
 8680                visible_row_range,
 8681                target_display_point,
 8682                line_height,
 8683                scroll_pixel_position,
 8684                content_origin,
 8685                editor_width,
 8686                window,
 8687                cx,
 8688            )
 8689        }
 8690    }
 8691
 8692    fn render_edit_prediction_end_of_line_popover(
 8693        self: &mut Editor,
 8694        label: &'static str,
 8695        editor_snapshot: &EditorSnapshot,
 8696        visible_row_range: Range<DisplayRow>,
 8697        target_display_point: DisplayPoint,
 8698        line_height: Pixels,
 8699        scroll_pixel_position: gpui::Point<Pixels>,
 8700        content_origin: gpui::Point<Pixels>,
 8701        editor_width: Pixels,
 8702        window: &mut Window,
 8703        cx: &mut App,
 8704    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8705        let target_line_end = DisplayPoint::new(
 8706            target_display_point.row(),
 8707            editor_snapshot.line_len(target_display_point.row()),
 8708        );
 8709
 8710        let mut element = self
 8711            .render_edit_prediction_line_popover(label, None, window, cx)?
 8712            .into_any();
 8713
 8714        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8715
 8716        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8717
 8718        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8719        let mut origin = start_point
 8720            + line_origin
 8721            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8722        origin.x = origin.x.max(content_origin.x);
 8723
 8724        let max_x = content_origin.x + editor_width - size.width;
 8725
 8726        if origin.x > max_x {
 8727            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8728
 8729            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8730                origin.y += offset;
 8731                IconName::ArrowUp
 8732            } else {
 8733                origin.y -= offset;
 8734                IconName::ArrowDown
 8735            };
 8736
 8737            element = self
 8738                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8739                .into_any();
 8740
 8741            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8742
 8743            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8744        }
 8745
 8746        element.prepaint_at(origin, window, cx);
 8747        Some((element, origin))
 8748    }
 8749
 8750    fn render_edit_prediction_diff_popover(
 8751        self: &Editor,
 8752        text_bounds: &Bounds<Pixels>,
 8753        content_origin: gpui::Point<Pixels>,
 8754        right_margin: Pixels,
 8755        editor_snapshot: &EditorSnapshot,
 8756        visible_row_range: Range<DisplayRow>,
 8757        line_layouts: &[LineWithInvisibles],
 8758        line_height: Pixels,
 8759        scroll_pixel_position: gpui::Point<Pixels>,
 8760        newest_selection_head: Option<DisplayPoint>,
 8761        editor_width: Pixels,
 8762        style: &EditorStyle,
 8763        edits: &Vec<(Range<Anchor>, String)>,
 8764        edit_preview: &Option<language::EditPreview>,
 8765        snapshot: &language::BufferSnapshot,
 8766        window: &mut Window,
 8767        cx: &mut App,
 8768    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8769        let edit_start = edits
 8770            .first()
 8771            .unwrap()
 8772            .0
 8773            .start
 8774            .to_display_point(editor_snapshot);
 8775        let edit_end = edits
 8776            .last()
 8777            .unwrap()
 8778            .0
 8779            .end
 8780            .to_display_point(editor_snapshot);
 8781
 8782        let is_visible = visible_row_range.contains(&edit_start.row())
 8783            || visible_row_range.contains(&edit_end.row());
 8784        if !is_visible {
 8785            return None;
 8786        }
 8787
 8788        let highlighted_edits =
 8789            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8790
 8791        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8792        let line_count = highlighted_edits.text.lines().count();
 8793
 8794        const BORDER_WIDTH: Pixels = px(1.);
 8795
 8796        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8797        let has_keybind = keybind.is_some();
 8798
 8799        let mut element = h_flex()
 8800            .items_start()
 8801            .child(
 8802                h_flex()
 8803                    .bg(cx.theme().colors().editor_background)
 8804                    .border(BORDER_WIDTH)
 8805                    .shadow_xs()
 8806                    .border_color(cx.theme().colors().border)
 8807                    .rounded_l_lg()
 8808                    .when(line_count > 1, |el| el.rounded_br_lg())
 8809                    .pr_1()
 8810                    .child(styled_text),
 8811            )
 8812            .child(
 8813                h_flex()
 8814                    .h(line_height + BORDER_WIDTH * 2.)
 8815                    .px_1p5()
 8816                    .gap_1()
 8817                    // Workaround: For some reason, there's a gap if we don't do this
 8818                    .ml(-BORDER_WIDTH)
 8819                    .shadow(vec![gpui::BoxShadow {
 8820                        color: gpui::black().opacity(0.05),
 8821                        offset: point(px(1.), px(1.)),
 8822                        blur_radius: px(2.),
 8823                        spread_radius: px(0.),
 8824                    }])
 8825                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8826                    .border(BORDER_WIDTH)
 8827                    .border_color(cx.theme().colors().border)
 8828                    .rounded_r_lg()
 8829                    .id("edit_prediction_diff_popover_keybind")
 8830                    .when(!has_keybind, |el| {
 8831                        let status_colors = cx.theme().status();
 8832
 8833                        el.bg(status_colors.error_background)
 8834                            .border_color(status_colors.error.opacity(0.6))
 8835                            .child(Icon::new(IconName::Info).color(Color::Error))
 8836                            .cursor_default()
 8837                            .hoverable_tooltip(move |_window, cx| {
 8838                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8839                            })
 8840                    })
 8841                    .children(keybind),
 8842            )
 8843            .into_any();
 8844
 8845        let longest_row =
 8846            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8847        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8848            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8849        } else {
 8850            layout_line(
 8851                longest_row,
 8852                editor_snapshot,
 8853                style,
 8854                editor_width,
 8855                |_| false,
 8856                window,
 8857                cx,
 8858            )
 8859            .width
 8860        };
 8861
 8862        let viewport_bounds =
 8863            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8864                right: -right_margin,
 8865                ..Default::default()
 8866            });
 8867
 8868        let x_after_longest =
 8869            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8870                - scroll_pixel_position.x;
 8871
 8872        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8873
 8874        // Fully visible if it can be displayed within the window (allow overlapping other
 8875        // panes). However, this is only allowed if the popover starts within text_bounds.
 8876        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8877            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8878
 8879        let mut origin = if can_position_to_the_right {
 8880            point(
 8881                x_after_longest,
 8882                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8883                    - scroll_pixel_position.y,
 8884            )
 8885        } else {
 8886            let cursor_row = newest_selection_head.map(|head| head.row());
 8887            let above_edit = edit_start
 8888                .row()
 8889                .0
 8890                .checked_sub(line_count as u32)
 8891                .map(DisplayRow);
 8892            let below_edit = Some(edit_end.row() + 1);
 8893            let above_cursor =
 8894                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8895            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8896
 8897            // Place the edit popover adjacent to the edit if there is a location
 8898            // available that is onscreen and does not obscure the cursor. Otherwise,
 8899            // place it adjacent to the cursor.
 8900            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8901                .into_iter()
 8902                .flatten()
 8903                .find(|&start_row| {
 8904                    let end_row = start_row + line_count as u32;
 8905                    visible_row_range.contains(&start_row)
 8906                        && visible_row_range.contains(&end_row)
 8907                        && cursor_row.map_or(true, |cursor_row| {
 8908                            !((start_row..end_row).contains(&cursor_row))
 8909                        })
 8910                })?;
 8911
 8912            content_origin
 8913                + point(
 8914                    -scroll_pixel_position.x,
 8915                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8916                )
 8917        };
 8918
 8919        origin.x -= BORDER_WIDTH;
 8920
 8921        window.defer_draw(element, origin, 1);
 8922
 8923        // Do not return an element, since it will already be drawn due to defer_draw.
 8924        None
 8925    }
 8926
 8927    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8928        px(30.)
 8929    }
 8930
 8931    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8932        if self.read_only(cx) {
 8933            cx.theme().players().read_only()
 8934        } else {
 8935            self.style.as_ref().unwrap().local_player
 8936        }
 8937    }
 8938
 8939    fn render_edit_prediction_accept_keybind(
 8940        &self,
 8941        window: &mut Window,
 8942        cx: &App,
 8943    ) -> Option<AnyElement> {
 8944        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8945        let accept_keystroke = accept_binding.keystroke()?;
 8946
 8947        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8948
 8949        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8950            Color::Accent
 8951        } else {
 8952            Color::Muted
 8953        };
 8954
 8955        h_flex()
 8956            .px_0p5()
 8957            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8958            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8959            .text_size(TextSize::XSmall.rems(cx))
 8960            .child(h_flex().children(ui::render_modifiers(
 8961                &accept_keystroke.modifiers,
 8962                PlatformStyle::platform(),
 8963                Some(modifiers_color),
 8964                Some(IconSize::XSmall.rems().into()),
 8965                true,
 8966            )))
 8967            .when(is_platform_style_mac, |parent| {
 8968                parent.child(accept_keystroke.key.clone())
 8969            })
 8970            .when(!is_platform_style_mac, |parent| {
 8971                parent.child(
 8972                    Key::new(
 8973                        util::capitalize(&accept_keystroke.key),
 8974                        Some(Color::Default),
 8975                    )
 8976                    .size(Some(IconSize::XSmall.rems().into())),
 8977                )
 8978            })
 8979            .into_any()
 8980            .into()
 8981    }
 8982
 8983    fn render_edit_prediction_line_popover(
 8984        &self,
 8985        label: impl Into<SharedString>,
 8986        icon: Option<IconName>,
 8987        window: &mut Window,
 8988        cx: &App,
 8989    ) -> Option<Stateful<Div>> {
 8990        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8991
 8992        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8993        let has_keybind = keybind.is_some();
 8994
 8995        let result = h_flex()
 8996            .id("ep-line-popover")
 8997            .py_0p5()
 8998            .pl_1()
 8999            .pr(padding_right)
 9000            .gap_1()
 9001            .rounded_md()
 9002            .border_1()
 9003            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9004            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9005            .shadow_xs()
 9006            .when(!has_keybind, |el| {
 9007                let status_colors = cx.theme().status();
 9008
 9009                el.bg(status_colors.error_background)
 9010                    .border_color(status_colors.error.opacity(0.6))
 9011                    .pl_2()
 9012                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9013                    .cursor_default()
 9014                    .hoverable_tooltip(move |_window, cx| {
 9015                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9016                    })
 9017            })
 9018            .children(keybind)
 9019            .child(
 9020                Label::new(label)
 9021                    .size(LabelSize::Small)
 9022                    .when(!has_keybind, |el| {
 9023                        el.color(cx.theme().status().error.into()).strikethrough()
 9024                    }),
 9025            )
 9026            .when(!has_keybind, |el| {
 9027                el.child(
 9028                    h_flex().ml_1().child(
 9029                        Icon::new(IconName::Info)
 9030                            .size(IconSize::Small)
 9031                            .color(cx.theme().status().error.into()),
 9032                    ),
 9033                )
 9034            })
 9035            .when_some(icon, |element, icon| {
 9036                element.child(
 9037                    div()
 9038                        .mt(px(1.5))
 9039                        .child(Icon::new(icon).size(IconSize::Small)),
 9040                )
 9041            });
 9042
 9043        Some(result)
 9044    }
 9045
 9046    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9047        let accent_color = cx.theme().colors().text_accent;
 9048        let editor_bg_color = cx.theme().colors().editor_background;
 9049        editor_bg_color.blend(accent_color.opacity(0.1))
 9050    }
 9051
 9052    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9053        let accent_color = cx.theme().colors().text_accent;
 9054        let editor_bg_color = cx.theme().colors().editor_background;
 9055        editor_bg_color.blend(accent_color.opacity(0.6))
 9056    }
 9057
 9058    fn render_edit_prediction_cursor_popover(
 9059        &self,
 9060        min_width: Pixels,
 9061        max_width: Pixels,
 9062        cursor_point: Point,
 9063        style: &EditorStyle,
 9064        accept_keystroke: Option<&gpui::Keystroke>,
 9065        _window: &Window,
 9066        cx: &mut Context<Editor>,
 9067    ) -> Option<AnyElement> {
 9068        let provider = self.edit_prediction_provider.as_ref()?;
 9069
 9070        if provider.provider.needs_terms_acceptance(cx) {
 9071            return Some(
 9072                h_flex()
 9073                    .min_w(min_width)
 9074                    .flex_1()
 9075                    .px_2()
 9076                    .py_1()
 9077                    .gap_3()
 9078                    .elevation_2(cx)
 9079                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9080                    .id("accept-terms")
 9081                    .cursor_pointer()
 9082                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9083                    .on_click(cx.listener(|this, _event, window, cx| {
 9084                        cx.stop_propagation();
 9085                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9086                        window.dispatch_action(
 9087                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9088                            cx,
 9089                        );
 9090                    }))
 9091                    .child(
 9092                        h_flex()
 9093                            .flex_1()
 9094                            .gap_2()
 9095                            .child(Icon::new(IconName::ZedPredict))
 9096                            .child(Label::new("Accept Terms of Service"))
 9097                            .child(div().w_full())
 9098                            .child(
 9099                                Icon::new(IconName::ArrowUpRight)
 9100                                    .color(Color::Muted)
 9101                                    .size(IconSize::Small),
 9102                            )
 9103                            .into_any_element(),
 9104                    )
 9105                    .into_any(),
 9106            );
 9107        }
 9108
 9109        let is_refreshing = provider.provider.is_refreshing(cx);
 9110
 9111        fn pending_completion_container() -> Div {
 9112            h_flex()
 9113                .h_full()
 9114                .flex_1()
 9115                .gap_2()
 9116                .child(Icon::new(IconName::ZedPredict))
 9117        }
 9118
 9119        let completion = match &self.active_inline_completion {
 9120            Some(prediction) => {
 9121                if !self.has_visible_completions_menu() {
 9122                    const RADIUS: Pixels = px(6.);
 9123                    const BORDER_WIDTH: Pixels = px(1.);
 9124
 9125                    return Some(
 9126                        h_flex()
 9127                            .elevation_2(cx)
 9128                            .border(BORDER_WIDTH)
 9129                            .border_color(cx.theme().colors().border)
 9130                            .when(accept_keystroke.is_none(), |el| {
 9131                                el.border_color(cx.theme().status().error)
 9132                            })
 9133                            .rounded(RADIUS)
 9134                            .rounded_tl(px(0.))
 9135                            .overflow_hidden()
 9136                            .child(div().px_1p5().child(match &prediction.completion {
 9137                                InlineCompletion::Move { target, snapshot } => {
 9138                                    use text::ToPoint as _;
 9139                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9140                                    {
 9141                                        Icon::new(IconName::ZedPredictDown)
 9142                                    } else {
 9143                                        Icon::new(IconName::ZedPredictUp)
 9144                                    }
 9145                                }
 9146                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9147                            }))
 9148                            .child(
 9149                                h_flex()
 9150                                    .gap_1()
 9151                                    .py_1()
 9152                                    .px_2()
 9153                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9154                                    .border_l_1()
 9155                                    .border_color(cx.theme().colors().border)
 9156                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9157                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9158                                        el.child(
 9159                                            Label::new("Hold")
 9160                                                .size(LabelSize::Small)
 9161                                                .when(accept_keystroke.is_none(), |el| {
 9162                                                    el.strikethrough()
 9163                                                })
 9164                                                .line_height_style(LineHeightStyle::UiLabel),
 9165                                        )
 9166                                    })
 9167                                    .id("edit_prediction_cursor_popover_keybind")
 9168                                    .when(accept_keystroke.is_none(), |el| {
 9169                                        let status_colors = cx.theme().status();
 9170
 9171                                        el.bg(status_colors.error_background)
 9172                                            .border_color(status_colors.error.opacity(0.6))
 9173                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9174                                            .cursor_default()
 9175                                            .hoverable_tooltip(move |_window, cx| {
 9176                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9177                                                    .into()
 9178                                            })
 9179                                    })
 9180                                    .when_some(
 9181                                        accept_keystroke.as_ref(),
 9182                                        |el, accept_keystroke| {
 9183                                            el.child(h_flex().children(ui::render_modifiers(
 9184                                                &accept_keystroke.modifiers,
 9185                                                PlatformStyle::platform(),
 9186                                                Some(Color::Default),
 9187                                                Some(IconSize::XSmall.rems().into()),
 9188                                                false,
 9189                                            )))
 9190                                        },
 9191                                    ),
 9192                            )
 9193                            .into_any(),
 9194                    );
 9195                }
 9196
 9197                self.render_edit_prediction_cursor_popover_preview(
 9198                    prediction,
 9199                    cursor_point,
 9200                    style,
 9201                    cx,
 9202                )?
 9203            }
 9204
 9205            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9206                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9207                    stale_completion,
 9208                    cursor_point,
 9209                    style,
 9210                    cx,
 9211                )?,
 9212
 9213                None => {
 9214                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9215                }
 9216            },
 9217
 9218            None => pending_completion_container().child(Label::new("No Prediction")),
 9219        };
 9220
 9221        let completion = if is_refreshing {
 9222            completion
 9223                .with_animation(
 9224                    "loading-completion",
 9225                    Animation::new(Duration::from_secs(2))
 9226                        .repeat()
 9227                        .with_easing(pulsating_between(0.4, 0.8)),
 9228                    |label, delta| label.opacity(delta),
 9229                )
 9230                .into_any_element()
 9231        } else {
 9232            completion.into_any_element()
 9233        };
 9234
 9235        let has_completion = self.active_inline_completion.is_some();
 9236
 9237        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9238        Some(
 9239            h_flex()
 9240                .min_w(min_width)
 9241                .max_w(max_width)
 9242                .flex_1()
 9243                .elevation_2(cx)
 9244                .border_color(cx.theme().colors().border)
 9245                .child(
 9246                    div()
 9247                        .flex_1()
 9248                        .py_1()
 9249                        .px_2()
 9250                        .overflow_hidden()
 9251                        .child(completion),
 9252                )
 9253                .when_some(accept_keystroke, |el, accept_keystroke| {
 9254                    if !accept_keystroke.modifiers.modified() {
 9255                        return el;
 9256                    }
 9257
 9258                    el.child(
 9259                        h_flex()
 9260                            .h_full()
 9261                            .border_l_1()
 9262                            .rounded_r_lg()
 9263                            .border_color(cx.theme().colors().border)
 9264                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9265                            .gap_1()
 9266                            .py_1()
 9267                            .px_2()
 9268                            .child(
 9269                                h_flex()
 9270                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9271                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9272                                    .child(h_flex().children(ui::render_modifiers(
 9273                                        &accept_keystroke.modifiers,
 9274                                        PlatformStyle::platform(),
 9275                                        Some(if !has_completion {
 9276                                            Color::Muted
 9277                                        } else {
 9278                                            Color::Default
 9279                                        }),
 9280                                        None,
 9281                                        false,
 9282                                    ))),
 9283                            )
 9284                            .child(Label::new("Preview").into_any_element())
 9285                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9286                    )
 9287                })
 9288                .into_any(),
 9289        )
 9290    }
 9291
 9292    fn render_edit_prediction_cursor_popover_preview(
 9293        &self,
 9294        completion: &InlineCompletionState,
 9295        cursor_point: Point,
 9296        style: &EditorStyle,
 9297        cx: &mut Context<Editor>,
 9298    ) -> Option<Div> {
 9299        use text::ToPoint as _;
 9300
 9301        fn render_relative_row_jump(
 9302            prefix: impl Into<String>,
 9303            current_row: u32,
 9304            target_row: u32,
 9305        ) -> Div {
 9306            let (row_diff, arrow) = if target_row < current_row {
 9307                (current_row - target_row, IconName::ArrowUp)
 9308            } else {
 9309                (target_row - current_row, IconName::ArrowDown)
 9310            };
 9311
 9312            h_flex()
 9313                .child(
 9314                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9315                        .color(Color::Muted)
 9316                        .size(LabelSize::Small),
 9317                )
 9318                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9319        }
 9320
 9321        match &completion.completion {
 9322            InlineCompletion::Move {
 9323                target, snapshot, ..
 9324            } => Some(
 9325                h_flex()
 9326                    .px_2()
 9327                    .gap_2()
 9328                    .flex_1()
 9329                    .child(
 9330                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9331                            Icon::new(IconName::ZedPredictDown)
 9332                        } else {
 9333                            Icon::new(IconName::ZedPredictUp)
 9334                        },
 9335                    )
 9336                    .child(Label::new("Jump to Edit")),
 9337            ),
 9338
 9339            InlineCompletion::Edit {
 9340                edits,
 9341                edit_preview,
 9342                snapshot,
 9343                display_mode: _,
 9344            } => {
 9345                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9346
 9347                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9348                    &snapshot,
 9349                    &edits,
 9350                    edit_preview.as_ref()?,
 9351                    true,
 9352                    cx,
 9353                )
 9354                .first_line_preview();
 9355
 9356                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9357                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9358
 9359                let preview = h_flex()
 9360                    .gap_1()
 9361                    .min_w_16()
 9362                    .child(styled_text)
 9363                    .when(has_more_lines, |parent| parent.child(""));
 9364
 9365                let left = if first_edit_row != cursor_point.row {
 9366                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9367                        .into_any_element()
 9368                } else {
 9369                    Icon::new(IconName::ZedPredict).into_any_element()
 9370                };
 9371
 9372                Some(
 9373                    h_flex()
 9374                        .h_full()
 9375                        .flex_1()
 9376                        .gap_2()
 9377                        .pr_1()
 9378                        .overflow_x_hidden()
 9379                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9380                        .child(left)
 9381                        .child(preview),
 9382                )
 9383            }
 9384        }
 9385    }
 9386
 9387    pub fn render_context_menu(
 9388        &self,
 9389        style: &EditorStyle,
 9390        max_height_in_lines: u32,
 9391        window: &mut Window,
 9392        cx: &mut Context<Editor>,
 9393    ) -> Option<AnyElement> {
 9394        let menu = self.context_menu.borrow();
 9395        let menu = menu.as_ref()?;
 9396        if !menu.visible() {
 9397            return None;
 9398        };
 9399        Some(menu.render(style, max_height_in_lines, window, cx))
 9400    }
 9401
 9402    fn render_context_menu_aside(
 9403        &mut self,
 9404        max_size: Size<Pixels>,
 9405        window: &mut Window,
 9406        cx: &mut Context<Editor>,
 9407    ) -> Option<AnyElement> {
 9408        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9409            if menu.visible() {
 9410                menu.render_aside(max_size, window, cx)
 9411            } else {
 9412                None
 9413            }
 9414        })
 9415    }
 9416
 9417    fn hide_context_menu(
 9418        &mut self,
 9419        window: &mut Window,
 9420        cx: &mut Context<Self>,
 9421    ) -> Option<CodeContextMenu> {
 9422        cx.notify();
 9423        self.completion_tasks.clear();
 9424        let context_menu = self.context_menu.borrow_mut().take();
 9425        self.stale_inline_completion_in_menu.take();
 9426        self.update_visible_inline_completion(window, cx);
 9427        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9428            if let Some(completion_provider) = &self.completion_provider {
 9429                completion_provider.selection_changed(None, window, cx);
 9430            }
 9431        }
 9432        context_menu
 9433    }
 9434
 9435    fn show_snippet_choices(
 9436        &mut self,
 9437        choices: &Vec<String>,
 9438        selection: Range<Anchor>,
 9439        cx: &mut Context<Self>,
 9440    ) {
 9441        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9442            (Some(a), Some(b)) if a == b => a,
 9443            _ => {
 9444                log::error!("expected anchor range to have matching buffer IDs");
 9445                return;
 9446            }
 9447        };
 9448        let multi_buffer = self.buffer().read(cx);
 9449        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9450            return;
 9451        };
 9452
 9453        let id = post_inc(&mut self.next_completion_id);
 9454        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9455        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9456            CompletionsMenu::new_snippet_choices(
 9457                id,
 9458                true,
 9459                choices,
 9460                selection,
 9461                buffer,
 9462                snippet_sort_order,
 9463            ),
 9464        ));
 9465    }
 9466
 9467    pub fn insert_snippet(
 9468        &mut self,
 9469        insertion_ranges: &[Range<usize>],
 9470        snippet: Snippet,
 9471        window: &mut Window,
 9472        cx: &mut Context<Self>,
 9473    ) -> Result<()> {
 9474        struct Tabstop<T> {
 9475            is_end_tabstop: bool,
 9476            ranges: Vec<Range<T>>,
 9477            choices: Option<Vec<String>>,
 9478        }
 9479
 9480        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9481            let snippet_text: Arc<str> = snippet.text.clone().into();
 9482            let edits = insertion_ranges
 9483                .iter()
 9484                .cloned()
 9485                .map(|range| (range, snippet_text.clone()));
 9486            let autoindent_mode = AutoindentMode::Block {
 9487                original_indent_columns: Vec::new(),
 9488            };
 9489            buffer.edit(edits, Some(autoindent_mode), cx);
 9490
 9491            let snapshot = &*buffer.read(cx);
 9492            let snippet = &snippet;
 9493            snippet
 9494                .tabstops
 9495                .iter()
 9496                .map(|tabstop| {
 9497                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9498                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9499                    });
 9500                    let mut tabstop_ranges = tabstop
 9501                        .ranges
 9502                        .iter()
 9503                        .flat_map(|tabstop_range| {
 9504                            let mut delta = 0_isize;
 9505                            insertion_ranges.iter().map(move |insertion_range| {
 9506                                let insertion_start = insertion_range.start as isize + delta;
 9507                                delta +=
 9508                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9509
 9510                                let start = ((insertion_start + tabstop_range.start) as usize)
 9511                                    .min(snapshot.len());
 9512                                let end = ((insertion_start + tabstop_range.end) as usize)
 9513                                    .min(snapshot.len());
 9514                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9515                            })
 9516                        })
 9517                        .collect::<Vec<_>>();
 9518                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9519
 9520                    Tabstop {
 9521                        is_end_tabstop,
 9522                        ranges: tabstop_ranges,
 9523                        choices: tabstop.choices.clone(),
 9524                    }
 9525                })
 9526                .collect::<Vec<_>>()
 9527        });
 9528        if let Some(tabstop) = tabstops.first() {
 9529            self.change_selections(Default::default(), window, cx, |s| {
 9530                // Reverse order so that the first range is the newest created selection.
 9531                // Completions will use it and autoscroll will prioritize it.
 9532                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9533            });
 9534
 9535            if let Some(choices) = &tabstop.choices {
 9536                if let Some(selection) = tabstop.ranges.first() {
 9537                    self.show_snippet_choices(choices, selection.clone(), cx)
 9538                }
 9539            }
 9540
 9541            // If we're already at the last tabstop and it's at the end of the snippet,
 9542            // we're done, we don't need to keep the state around.
 9543            if !tabstop.is_end_tabstop {
 9544                let choices = tabstops
 9545                    .iter()
 9546                    .map(|tabstop| tabstop.choices.clone())
 9547                    .collect();
 9548
 9549                let ranges = tabstops
 9550                    .into_iter()
 9551                    .map(|tabstop| tabstop.ranges)
 9552                    .collect::<Vec<_>>();
 9553
 9554                self.snippet_stack.push(SnippetState {
 9555                    active_index: 0,
 9556                    ranges,
 9557                    choices,
 9558                });
 9559            }
 9560
 9561            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9562            if self.autoclose_regions.is_empty() {
 9563                let snapshot = self.buffer.read(cx).snapshot(cx);
 9564                for selection in &mut self.selections.all::<Point>(cx) {
 9565                    let selection_head = selection.head();
 9566                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9567                        continue;
 9568                    };
 9569
 9570                    let mut bracket_pair = None;
 9571                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9572                    let prev_chars = snapshot
 9573                        .reversed_chars_at(selection_head)
 9574                        .collect::<String>();
 9575                    for (pair, enabled) in scope.brackets() {
 9576                        if enabled
 9577                            && pair.close
 9578                            && prev_chars.starts_with(pair.start.as_str())
 9579                            && next_chars.starts_with(pair.end.as_str())
 9580                        {
 9581                            bracket_pair = Some(pair.clone());
 9582                            break;
 9583                        }
 9584                    }
 9585                    if let Some(pair) = bracket_pair {
 9586                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9587                        let autoclose_enabled =
 9588                            self.use_autoclose && snapshot_settings.use_autoclose;
 9589                        if autoclose_enabled {
 9590                            let start = snapshot.anchor_after(selection_head);
 9591                            let end = snapshot.anchor_after(selection_head);
 9592                            self.autoclose_regions.push(AutocloseRegion {
 9593                                selection_id: selection.id,
 9594                                range: start..end,
 9595                                pair,
 9596                            });
 9597                        }
 9598                    }
 9599                }
 9600            }
 9601        }
 9602        Ok(())
 9603    }
 9604
 9605    pub fn move_to_next_snippet_tabstop(
 9606        &mut self,
 9607        window: &mut Window,
 9608        cx: &mut Context<Self>,
 9609    ) -> bool {
 9610        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9611    }
 9612
 9613    pub fn move_to_prev_snippet_tabstop(
 9614        &mut self,
 9615        window: &mut Window,
 9616        cx: &mut Context<Self>,
 9617    ) -> bool {
 9618        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9619    }
 9620
 9621    pub fn move_to_snippet_tabstop(
 9622        &mut self,
 9623        bias: Bias,
 9624        window: &mut Window,
 9625        cx: &mut Context<Self>,
 9626    ) -> bool {
 9627        if let Some(mut snippet) = self.snippet_stack.pop() {
 9628            match bias {
 9629                Bias::Left => {
 9630                    if snippet.active_index > 0 {
 9631                        snippet.active_index -= 1;
 9632                    } else {
 9633                        self.snippet_stack.push(snippet);
 9634                        return false;
 9635                    }
 9636                }
 9637                Bias::Right => {
 9638                    if snippet.active_index + 1 < snippet.ranges.len() {
 9639                        snippet.active_index += 1;
 9640                    } else {
 9641                        self.snippet_stack.push(snippet);
 9642                        return false;
 9643                    }
 9644                }
 9645            }
 9646            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9647                self.change_selections(Default::default(), window, cx, |s| {
 9648                    // Reverse order so that the first range is the newest created selection.
 9649                    // Completions will use it and autoscroll will prioritize it.
 9650                    s.select_ranges(current_ranges.iter().rev().cloned())
 9651                });
 9652
 9653                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9654                    if let Some(selection) = current_ranges.first() {
 9655                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9656                    }
 9657                }
 9658
 9659                // If snippet state is not at the last tabstop, push it back on the stack
 9660                if snippet.active_index + 1 < snippet.ranges.len() {
 9661                    self.snippet_stack.push(snippet);
 9662                }
 9663                return true;
 9664            }
 9665        }
 9666
 9667        false
 9668    }
 9669
 9670    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9671        self.transact(window, cx, |this, window, cx| {
 9672            this.select_all(&SelectAll, window, cx);
 9673            this.insert("", window, cx);
 9674        });
 9675    }
 9676
 9677    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9679        self.transact(window, cx, |this, window, cx| {
 9680            this.select_autoclose_pair(window, cx);
 9681            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9682            if !this.linked_edit_ranges.is_empty() {
 9683                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9684                let snapshot = this.buffer.read(cx).snapshot(cx);
 9685
 9686                for selection in selections.iter() {
 9687                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9688                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9689                    if selection_start.buffer_id != selection_end.buffer_id {
 9690                        continue;
 9691                    }
 9692                    if let Some(ranges) =
 9693                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9694                    {
 9695                        for (buffer, entries) in ranges {
 9696                            linked_ranges.entry(buffer).or_default().extend(entries);
 9697                        }
 9698                    }
 9699                }
 9700            }
 9701
 9702            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9703            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9704            for selection in &mut selections {
 9705                if selection.is_empty() {
 9706                    let old_head = selection.head();
 9707                    let mut new_head =
 9708                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9709                            .to_point(&display_map);
 9710                    if let Some((buffer, line_buffer_range)) = display_map
 9711                        .buffer_snapshot
 9712                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9713                    {
 9714                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9715                        let indent_len = match indent_size.kind {
 9716                            IndentKind::Space => {
 9717                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9718                            }
 9719                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9720                        };
 9721                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9722                            let indent_len = indent_len.get();
 9723                            new_head = cmp::min(
 9724                                new_head,
 9725                                MultiBufferPoint::new(
 9726                                    old_head.row,
 9727                                    ((old_head.column - 1) / indent_len) * indent_len,
 9728                                ),
 9729                            );
 9730                        }
 9731                    }
 9732
 9733                    selection.set_head(new_head, SelectionGoal::None);
 9734                }
 9735            }
 9736
 9737            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9738            this.insert("", window, cx);
 9739            let empty_str: Arc<str> = Arc::from("");
 9740            for (buffer, edits) in linked_ranges {
 9741                let snapshot = buffer.read(cx).snapshot();
 9742                use text::ToPoint as TP;
 9743
 9744                let edits = edits
 9745                    .into_iter()
 9746                    .map(|range| {
 9747                        let end_point = TP::to_point(&range.end, &snapshot);
 9748                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9749
 9750                        if end_point == start_point {
 9751                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9752                                .saturating_sub(1);
 9753                            start_point =
 9754                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9755                        };
 9756
 9757                        (start_point..end_point, empty_str.clone())
 9758                    })
 9759                    .sorted_by_key(|(range, _)| range.start)
 9760                    .collect::<Vec<_>>();
 9761                buffer.update(cx, |this, cx| {
 9762                    this.edit(edits, None, cx);
 9763                })
 9764            }
 9765            this.refresh_inline_completion(true, false, window, cx);
 9766            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9767        });
 9768    }
 9769
 9770    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9772        self.transact(window, cx, |this, window, cx| {
 9773            this.change_selections(Default::default(), window, cx, |s| {
 9774                s.move_with(|map, selection| {
 9775                    if selection.is_empty() {
 9776                        let cursor = movement::right(map, selection.head());
 9777                        selection.end = cursor;
 9778                        selection.reversed = true;
 9779                        selection.goal = SelectionGoal::None;
 9780                    }
 9781                })
 9782            });
 9783            this.insert("", window, cx);
 9784            this.refresh_inline_completion(true, false, window, cx);
 9785        });
 9786    }
 9787
 9788    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9789        if self.mode.is_single_line() {
 9790            cx.propagate();
 9791            return;
 9792        }
 9793
 9794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9795        if self.move_to_prev_snippet_tabstop(window, cx) {
 9796            return;
 9797        }
 9798        self.outdent(&Outdent, window, cx);
 9799    }
 9800
 9801    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9802        if self.mode.is_single_line() {
 9803            cx.propagate();
 9804            return;
 9805        }
 9806
 9807        if self.move_to_next_snippet_tabstop(window, cx) {
 9808            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9809            return;
 9810        }
 9811        if self.read_only(cx) {
 9812            return;
 9813        }
 9814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9815        let mut selections = self.selections.all_adjusted(cx);
 9816        let buffer = self.buffer.read(cx);
 9817        let snapshot = buffer.snapshot(cx);
 9818        let rows_iter = selections.iter().map(|s| s.head().row);
 9819        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9820
 9821        let has_some_cursor_in_whitespace = selections
 9822            .iter()
 9823            .filter(|selection| selection.is_empty())
 9824            .any(|selection| {
 9825                let cursor = selection.head();
 9826                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9827                cursor.column < current_indent.len
 9828            });
 9829
 9830        let mut edits = Vec::new();
 9831        let mut prev_edited_row = 0;
 9832        let mut row_delta = 0;
 9833        for selection in &mut selections {
 9834            if selection.start.row != prev_edited_row {
 9835                row_delta = 0;
 9836            }
 9837            prev_edited_row = selection.end.row;
 9838
 9839            // If the selection is non-empty, then increase the indentation of the selected lines.
 9840            if !selection.is_empty() {
 9841                row_delta =
 9842                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9843                continue;
 9844            }
 9845
 9846            let cursor = selection.head();
 9847            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9848            if let Some(suggested_indent) =
 9849                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9850            {
 9851                // Don't do anything if already at suggested indent
 9852                // and there is any other cursor which is not
 9853                if has_some_cursor_in_whitespace
 9854                    && cursor.column == current_indent.len
 9855                    && current_indent.len == suggested_indent.len
 9856                {
 9857                    continue;
 9858                }
 9859
 9860                // Adjust line and move cursor to suggested indent
 9861                // if cursor is not at suggested indent
 9862                if cursor.column < suggested_indent.len
 9863                    && cursor.column <= current_indent.len
 9864                    && current_indent.len <= suggested_indent.len
 9865                {
 9866                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9867                    selection.end = selection.start;
 9868                    if row_delta == 0 {
 9869                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9870                            cursor.row,
 9871                            current_indent,
 9872                            suggested_indent,
 9873                        ));
 9874                        row_delta = suggested_indent.len - current_indent.len;
 9875                    }
 9876                    continue;
 9877                }
 9878
 9879                // If current indent is more than suggested indent
 9880                // only move cursor to current indent and skip indent
 9881                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9882                    selection.start = Point::new(cursor.row, current_indent.len);
 9883                    selection.end = selection.start;
 9884                    continue;
 9885                }
 9886            }
 9887
 9888            // Otherwise, insert a hard or soft tab.
 9889            let settings = buffer.language_settings_at(cursor, cx);
 9890            let tab_size = if settings.hard_tabs {
 9891                IndentSize::tab()
 9892            } else {
 9893                let tab_size = settings.tab_size.get();
 9894                let indent_remainder = snapshot
 9895                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9896                    .flat_map(str::chars)
 9897                    .fold(row_delta % tab_size, |counter: u32, c| {
 9898                        if c == '\t' {
 9899                            0
 9900                        } else {
 9901                            (counter + 1) % tab_size
 9902                        }
 9903                    });
 9904
 9905                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9906                IndentSize::spaces(chars_to_next_tab_stop)
 9907            };
 9908            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9909            selection.end = selection.start;
 9910            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9911            row_delta += tab_size.len;
 9912        }
 9913
 9914        self.transact(window, cx, |this, window, cx| {
 9915            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9916            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9917            this.refresh_inline_completion(true, false, window, cx);
 9918        });
 9919    }
 9920
 9921    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9922        if self.read_only(cx) {
 9923            return;
 9924        }
 9925        if self.mode.is_single_line() {
 9926            cx.propagate();
 9927            return;
 9928        }
 9929
 9930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9931        let mut selections = self.selections.all::<Point>(cx);
 9932        let mut prev_edited_row = 0;
 9933        let mut row_delta = 0;
 9934        let mut edits = Vec::new();
 9935        let buffer = self.buffer.read(cx);
 9936        let snapshot = buffer.snapshot(cx);
 9937        for selection in &mut selections {
 9938            if selection.start.row != prev_edited_row {
 9939                row_delta = 0;
 9940            }
 9941            prev_edited_row = selection.end.row;
 9942
 9943            row_delta =
 9944                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9945        }
 9946
 9947        self.transact(window, cx, |this, window, cx| {
 9948            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9949            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9950        });
 9951    }
 9952
 9953    fn indent_selection(
 9954        buffer: &MultiBuffer,
 9955        snapshot: &MultiBufferSnapshot,
 9956        selection: &mut Selection<Point>,
 9957        edits: &mut Vec<(Range<Point>, String)>,
 9958        delta_for_start_row: u32,
 9959        cx: &App,
 9960    ) -> u32 {
 9961        let settings = buffer.language_settings_at(selection.start, cx);
 9962        let tab_size = settings.tab_size.get();
 9963        let indent_kind = if settings.hard_tabs {
 9964            IndentKind::Tab
 9965        } else {
 9966            IndentKind::Space
 9967        };
 9968        let mut start_row = selection.start.row;
 9969        let mut end_row = selection.end.row + 1;
 9970
 9971        // If a selection ends at the beginning of a line, don't indent
 9972        // that last line.
 9973        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9974            end_row -= 1;
 9975        }
 9976
 9977        // Avoid re-indenting a row that has already been indented by a
 9978        // previous selection, but still update this selection's column
 9979        // to reflect that indentation.
 9980        if delta_for_start_row > 0 {
 9981            start_row += 1;
 9982            selection.start.column += delta_for_start_row;
 9983            if selection.end.row == selection.start.row {
 9984                selection.end.column += delta_for_start_row;
 9985            }
 9986        }
 9987
 9988        let mut delta_for_end_row = 0;
 9989        let has_multiple_rows = start_row + 1 != end_row;
 9990        for row in start_row..end_row {
 9991            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9992            let indent_delta = match (current_indent.kind, indent_kind) {
 9993                (IndentKind::Space, IndentKind::Space) => {
 9994                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9995                    IndentSize::spaces(columns_to_next_tab_stop)
 9996                }
 9997                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9998                (_, IndentKind::Tab) => IndentSize::tab(),
 9999            };
10000
10001            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10002                0
10003            } else {
10004                selection.start.column
10005            };
10006            let row_start = Point::new(row, start);
10007            edits.push((
10008                row_start..row_start,
10009                indent_delta.chars().collect::<String>(),
10010            ));
10011
10012            // Update this selection's endpoints to reflect the indentation.
10013            if row == selection.start.row {
10014                selection.start.column += indent_delta.len;
10015            }
10016            if row == selection.end.row {
10017                selection.end.column += indent_delta.len;
10018                delta_for_end_row = indent_delta.len;
10019            }
10020        }
10021
10022        if selection.start.row == selection.end.row {
10023            delta_for_start_row + delta_for_end_row
10024        } else {
10025            delta_for_end_row
10026        }
10027    }
10028
10029    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10030        if self.read_only(cx) {
10031            return;
10032        }
10033        if self.mode.is_single_line() {
10034            cx.propagate();
10035            return;
10036        }
10037
10038        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10039        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10040        let selections = self.selections.all::<Point>(cx);
10041        let mut deletion_ranges = Vec::new();
10042        let mut last_outdent = None;
10043        {
10044            let buffer = self.buffer.read(cx);
10045            let snapshot = buffer.snapshot(cx);
10046            for selection in &selections {
10047                let settings = buffer.language_settings_at(selection.start, cx);
10048                let tab_size = settings.tab_size.get();
10049                let mut rows = selection.spanned_rows(false, &display_map);
10050
10051                // Avoid re-outdenting a row that has already been outdented by a
10052                // previous selection.
10053                if let Some(last_row) = last_outdent {
10054                    if last_row == rows.start {
10055                        rows.start = rows.start.next_row();
10056                    }
10057                }
10058                let has_multiple_rows = rows.len() > 1;
10059                for row in rows.iter_rows() {
10060                    let indent_size = snapshot.indent_size_for_line(row);
10061                    if indent_size.len > 0 {
10062                        let deletion_len = match indent_size.kind {
10063                            IndentKind::Space => {
10064                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10065                                if columns_to_prev_tab_stop == 0 {
10066                                    tab_size
10067                                } else {
10068                                    columns_to_prev_tab_stop
10069                                }
10070                            }
10071                            IndentKind::Tab => 1,
10072                        };
10073                        let start = if has_multiple_rows
10074                            || deletion_len > selection.start.column
10075                            || indent_size.len < selection.start.column
10076                        {
10077                            0
10078                        } else {
10079                            selection.start.column - deletion_len
10080                        };
10081                        deletion_ranges.push(
10082                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10083                        );
10084                        last_outdent = Some(row);
10085                    }
10086                }
10087            }
10088        }
10089
10090        self.transact(window, cx, |this, window, cx| {
10091            this.buffer.update(cx, |buffer, cx| {
10092                let empty_str: Arc<str> = Arc::default();
10093                buffer.edit(
10094                    deletion_ranges
10095                        .into_iter()
10096                        .map(|range| (range, empty_str.clone())),
10097                    None,
10098                    cx,
10099                );
10100            });
10101            let selections = this.selections.all::<usize>(cx);
10102            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10103        });
10104    }
10105
10106    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        let selections = self
10117            .selections
10118            .all::<usize>(cx)
10119            .into_iter()
10120            .map(|s| s.range());
10121
10122        self.transact(window, cx, |this, window, cx| {
10123            this.buffer.update(cx, |buffer, cx| {
10124                buffer.autoindent_ranges(selections, cx);
10125            });
10126            let selections = this.selections.all::<usize>(cx);
10127            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10128        });
10129    }
10130
10131    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10133        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10134        let selections = self.selections.all::<Point>(cx);
10135
10136        let mut new_cursors = Vec::new();
10137        let mut edit_ranges = Vec::new();
10138        let mut selections = selections.iter().peekable();
10139        while let Some(selection) = selections.next() {
10140            let mut rows = selection.spanned_rows(false, &display_map);
10141            let goal_display_column = selection.head().to_display_point(&display_map).column();
10142
10143            // Accumulate contiguous regions of rows that we want to delete.
10144            while let Some(next_selection) = selections.peek() {
10145                let next_rows = next_selection.spanned_rows(false, &display_map);
10146                if next_rows.start <= rows.end {
10147                    rows.end = next_rows.end;
10148                    selections.next().unwrap();
10149                } else {
10150                    break;
10151                }
10152            }
10153
10154            let buffer = &display_map.buffer_snapshot;
10155            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10156            let edit_end;
10157            let cursor_buffer_row;
10158            if buffer.max_point().row >= rows.end.0 {
10159                // If there's a line after the range, delete the \n from the end of the row range
10160                // and position the cursor on the next line.
10161                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10162                cursor_buffer_row = rows.end;
10163            } else {
10164                // If there isn't a line after the range, delete the \n from the line before the
10165                // start of the row range and position the cursor there.
10166                edit_start = edit_start.saturating_sub(1);
10167                edit_end = buffer.len();
10168                cursor_buffer_row = rows.start.previous_row();
10169            }
10170
10171            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10172            *cursor.column_mut() =
10173                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10174
10175            new_cursors.push((
10176                selection.id,
10177                buffer.anchor_after(cursor.to_point(&display_map)),
10178            ));
10179            edit_ranges.push(edit_start..edit_end);
10180        }
10181
10182        self.transact(window, cx, |this, window, cx| {
10183            let buffer = this.buffer.update(cx, |buffer, cx| {
10184                let empty_str: Arc<str> = Arc::default();
10185                buffer.edit(
10186                    edit_ranges
10187                        .into_iter()
10188                        .map(|range| (range, empty_str.clone())),
10189                    None,
10190                    cx,
10191                );
10192                buffer.snapshot(cx)
10193            });
10194            let new_selections = new_cursors
10195                .into_iter()
10196                .map(|(id, cursor)| {
10197                    let cursor = cursor.to_point(&buffer);
10198                    Selection {
10199                        id,
10200                        start: cursor,
10201                        end: cursor,
10202                        reversed: false,
10203                        goal: SelectionGoal::None,
10204                    }
10205                })
10206                .collect();
10207
10208            this.change_selections(Default::default(), window, cx, |s| {
10209                s.select(new_selections);
10210            });
10211        });
10212    }
10213
10214    pub fn join_lines_impl(
10215        &mut self,
10216        insert_whitespace: bool,
10217        window: &mut Window,
10218        cx: &mut Context<Self>,
10219    ) {
10220        if self.read_only(cx) {
10221            return;
10222        }
10223        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10224        for selection in self.selections.all::<Point>(cx) {
10225            let start = MultiBufferRow(selection.start.row);
10226            // Treat single line selections as if they include the next line. Otherwise this action
10227            // would do nothing for single line selections individual cursors.
10228            let end = if selection.start.row == selection.end.row {
10229                MultiBufferRow(selection.start.row + 1)
10230            } else {
10231                MultiBufferRow(selection.end.row)
10232            };
10233
10234            if let Some(last_row_range) = row_ranges.last_mut() {
10235                if start <= last_row_range.end {
10236                    last_row_range.end = end;
10237                    continue;
10238                }
10239            }
10240            row_ranges.push(start..end);
10241        }
10242
10243        let snapshot = self.buffer.read(cx).snapshot(cx);
10244        let mut cursor_positions = Vec::new();
10245        for row_range in &row_ranges {
10246            let anchor = snapshot.anchor_before(Point::new(
10247                row_range.end.previous_row().0,
10248                snapshot.line_len(row_range.end.previous_row()),
10249            ));
10250            cursor_positions.push(anchor..anchor);
10251        }
10252
10253        self.transact(window, cx, |this, window, cx| {
10254            for row_range in row_ranges.into_iter().rev() {
10255                for row in row_range.iter_rows().rev() {
10256                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10257                    let next_line_row = row.next_row();
10258                    let indent = snapshot.indent_size_for_line(next_line_row);
10259                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10260
10261                    let replace =
10262                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10263                            " "
10264                        } else {
10265                            ""
10266                        };
10267
10268                    this.buffer.update(cx, |buffer, cx| {
10269                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10270                    });
10271                }
10272            }
10273
10274            this.change_selections(Default::default(), window, cx, |s| {
10275                s.select_anchor_ranges(cursor_positions)
10276            });
10277        });
10278    }
10279
10280    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10282        self.join_lines_impl(true, window, cx);
10283    }
10284
10285    pub fn sort_lines_case_sensitive(
10286        &mut self,
10287        _: &SortLinesCaseSensitive,
10288        window: &mut Window,
10289        cx: &mut Context<Self>,
10290    ) {
10291        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10292    }
10293
10294    pub fn sort_lines_by_length(
10295        &mut self,
10296        _: &SortLinesByLength,
10297        window: &mut Window,
10298        cx: &mut Context<Self>,
10299    ) {
10300        self.manipulate_immutable_lines(window, cx, |lines| {
10301            lines.sort_by_key(|&line| line.chars().count())
10302        })
10303    }
10304
10305    pub fn sort_lines_case_insensitive(
10306        &mut self,
10307        _: &SortLinesCaseInsensitive,
10308        window: &mut Window,
10309        cx: &mut Context<Self>,
10310    ) {
10311        self.manipulate_immutable_lines(window, cx, |lines| {
10312            lines.sort_by_key(|line| line.to_lowercase())
10313        })
10314    }
10315
10316    pub fn unique_lines_case_insensitive(
10317        &mut self,
10318        _: &UniqueLinesCaseInsensitive,
10319        window: &mut Window,
10320        cx: &mut Context<Self>,
10321    ) {
10322        self.manipulate_immutable_lines(window, cx, |lines| {
10323            let mut seen = HashSet::default();
10324            lines.retain(|line| seen.insert(line.to_lowercase()));
10325        })
10326    }
10327
10328    pub fn unique_lines_case_sensitive(
10329        &mut self,
10330        _: &UniqueLinesCaseSensitive,
10331        window: &mut Window,
10332        cx: &mut Context<Self>,
10333    ) {
10334        self.manipulate_immutable_lines(window, cx, |lines| {
10335            let mut seen = HashSet::default();
10336            lines.retain(|line| seen.insert(*line));
10337        })
10338    }
10339
10340    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10341        let Some(project) = self.project.clone() else {
10342            return;
10343        };
10344        self.reload(project, window, cx)
10345            .detach_and_notify_err(window, cx);
10346    }
10347
10348    pub fn restore_file(
10349        &mut self,
10350        _: &::git::RestoreFile,
10351        window: &mut Window,
10352        cx: &mut Context<Self>,
10353    ) {
10354        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10355        let mut buffer_ids = HashSet::default();
10356        let snapshot = self.buffer().read(cx).snapshot(cx);
10357        for selection in self.selections.all::<usize>(cx) {
10358            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10359        }
10360
10361        let buffer = self.buffer().read(cx);
10362        let ranges = buffer_ids
10363            .into_iter()
10364            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10365            .collect::<Vec<_>>();
10366
10367        self.restore_hunks_in_ranges(ranges, window, cx);
10368    }
10369
10370    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10372        let selections = self
10373            .selections
10374            .all(cx)
10375            .into_iter()
10376            .map(|s| s.range())
10377            .collect();
10378        self.restore_hunks_in_ranges(selections, window, cx);
10379    }
10380
10381    pub fn restore_hunks_in_ranges(
10382        &mut self,
10383        ranges: Vec<Range<Point>>,
10384        window: &mut Window,
10385        cx: &mut Context<Editor>,
10386    ) {
10387        let mut revert_changes = HashMap::default();
10388        let chunk_by = self
10389            .snapshot(window, cx)
10390            .hunks_for_ranges(ranges)
10391            .into_iter()
10392            .chunk_by(|hunk| hunk.buffer_id);
10393        for (buffer_id, hunks) in &chunk_by {
10394            let hunks = hunks.collect::<Vec<_>>();
10395            for hunk in &hunks {
10396                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10397            }
10398            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10399        }
10400        drop(chunk_by);
10401        if !revert_changes.is_empty() {
10402            self.transact(window, cx, |editor, window, cx| {
10403                editor.restore(revert_changes, window, cx);
10404            });
10405        }
10406    }
10407
10408    pub fn open_active_item_in_terminal(
10409        &mut self,
10410        _: &OpenInTerminal,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10415            let project_path = buffer.read(cx).project_path(cx)?;
10416            let project = self.project.as_ref()?.read(cx);
10417            let entry = project.entry_for_path(&project_path, cx)?;
10418            let parent = match &entry.canonical_path {
10419                Some(canonical_path) => canonical_path.to_path_buf(),
10420                None => project.absolute_path(&project_path, cx)?,
10421            }
10422            .parent()?
10423            .to_path_buf();
10424            Some(parent)
10425        }) {
10426            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10427        }
10428    }
10429
10430    fn set_breakpoint_context_menu(
10431        &mut self,
10432        display_row: DisplayRow,
10433        position: Option<Anchor>,
10434        clicked_point: gpui::Point<Pixels>,
10435        window: &mut Window,
10436        cx: &mut Context<Self>,
10437    ) {
10438        let source = self
10439            .buffer
10440            .read(cx)
10441            .snapshot(cx)
10442            .anchor_before(Point::new(display_row.0, 0u32));
10443
10444        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10445
10446        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10447            self,
10448            source,
10449            clicked_point,
10450            context_menu,
10451            window,
10452            cx,
10453        );
10454    }
10455
10456    fn add_edit_breakpoint_block(
10457        &mut self,
10458        anchor: Anchor,
10459        breakpoint: &Breakpoint,
10460        edit_action: BreakpointPromptEditAction,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        let weak_editor = cx.weak_entity();
10465        let bp_prompt = cx.new(|cx| {
10466            BreakpointPromptEditor::new(
10467                weak_editor,
10468                anchor,
10469                breakpoint.clone(),
10470                edit_action,
10471                window,
10472                cx,
10473            )
10474        });
10475
10476        let height = bp_prompt.update(cx, |this, cx| {
10477            this.prompt
10478                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10479        });
10480        let cloned_prompt = bp_prompt.clone();
10481        let blocks = vec![BlockProperties {
10482            style: BlockStyle::Sticky,
10483            placement: BlockPlacement::Above(anchor),
10484            height: Some(height),
10485            render: Arc::new(move |cx| {
10486                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10487                cloned_prompt.clone().into_any_element()
10488            }),
10489            priority: 0,
10490        }];
10491
10492        let focus_handle = bp_prompt.focus_handle(cx);
10493        window.focus(&focus_handle);
10494
10495        let block_ids = self.insert_blocks(blocks, None, cx);
10496        bp_prompt.update(cx, |prompt, _| {
10497            prompt.add_block_ids(block_ids);
10498        });
10499    }
10500
10501    pub(crate) fn breakpoint_at_row(
10502        &self,
10503        row: u32,
10504        window: &mut Window,
10505        cx: &mut Context<Self>,
10506    ) -> Option<(Anchor, Breakpoint)> {
10507        let snapshot = self.snapshot(window, cx);
10508        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10509
10510        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10511    }
10512
10513    pub(crate) fn breakpoint_at_anchor(
10514        &self,
10515        breakpoint_position: Anchor,
10516        snapshot: &EditorSnapshot,
10517        cx: &mut Context<Self>,
10518    ) -> Option<(Anchor, Breakpoint)> {
10519        let project = self.project.clone()?;
10520
10521        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10522            snapshot
10523                .buffer_snapshot
10524                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10525        })?;
10526
10527        let enclosing_excerpt = breakpoint_position.excerpt_id;
10528        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10529        let buffer_snapshot = buffer.read(cx).snapshot();
10530
10531        let row = buffer_snapshot
10532            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10533            .row;
10534
10535        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10536        let anchor_end = snapshot
10537            .buffer_snapshot
10538            .anchor_after(Point::new(row, line_len));
10539
10540        let bp = self
10541            .breakpoint_store
10542            .as_ref()?
10543            .read_with(cx, |breakpoint_store, cx| {
10544                breakpoint_store
10545                    .breakpoints(
10546                        &buffer,
10547                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10548                        &buffer_snapshot,
10549                        cx,
10550                    )
10551                    .next()
10552                    .and_then(|(bp, _)| {
10553                        let breakpoint_row = buffer_snapshot
10554                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10555                            .row;
10556
10557                        if breakpoint_row == row {
10558                            snapshot
10559                                .buffer_snapshot
10560                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10561                                .map(|position| (position, bp.bp.clone()))
10562                        } else {
10563                            None
10564                        }
10565                    })
10566            });
10567        bp
10568    }
10569
10570    pub fn edit_log_breakpoint(
10571        &mut self,
10572        _: &EditLogBreakpoint,
10573        window: &mut Window,
10574        cx: &mut Context<Self>,
10575    ) {
10576        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10577            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10578                message: None,
10579                state: BreakpointState::Enabled,
10580                condition: None,
10581                hit_condition: None,
10582            });
10583
10584            self.add_edit_breakpoint_block(
10585                anchor,
10586                &breakpoint,
10587                BreakpointPromptEditAction::Log,
10588                window,
10589                cx,
10590            );
10591        }
10592    }
10593
10594    fn breakpoints_at_cursors(
10595        &self,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10599        let snapshot = self.snapshot(window, cx);
10600        let cursors = self
10601            .selections
10602            .disjoint_anchors()
10603            .into_iter()
10604            .map(|selection| {
10605                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10606
10607                let breakpoint_position = self
10608                    .breakpoint_at_row(cursor_position.row, window, cx)
10609                    .map(|bp| bp.0)
10610                    .unwrap_or_else(|| {
10611                        snapshot
10612                            .display_snapshot
10613                            .buffer_snapshot
10614                            .anchor_after(Point::new(cursor_position.row, 0))
10615                    });
10616
10617                let breakpoint = self
10618                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10619                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10620
10621                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10622            })
10623            // 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.
10624            .collect::<HashMap<Anchor, _>>();
10625
10626        cursors.into_iter().collect()
10627    }
10628
10629    pub fn enable_breakpoint(
10630        &mut self,
10631        _: &crate::actions::EnableBreakpoint,
10632        window: &mut Window,
10633        cx: &mut Context<Self>,
10634    ) {
10635        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10636            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10637                continue;
10638            };
10639            self.edit_breakpoint_at_anchor(
10640                anchor,
10641                breakpoint,
10642                BreakpointEditAction::InvertState,
10643                cx,
10644            );
10645        }
10646    }
10647
10648    pub fn disable_breakpoint(
10649        &mut self,
10650        _: &crate::actions::DisableBreakpoint,
10651        window: &mut Window,
10652        cx: &mut Context<Self>,
10653    ) {
10654        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10655            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10656                continue;
10657            };
10658            self.edit_breakpoint_at_anchor(
10659                anchor,
10660                breakpoint,
10661                BreakpointEditAction::InvertState,
10662                cx,
10663            );
10664        }
10665    }
10666
10667    pub fn toggle_breakpoint(
10668        &mut self,
10669        _: &crate::actions::ToggleBreakpoint,
10670        window: &mut Window,
10671        cx: &mut Context<Self>,
10672    ) {
10673        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10674            if let Some(breakpoint) = breakpoint {
10675                self.edit_breakpoint_at_anchor(
10676                    anchor,
10677                    breakpoint,
10678                    BreakpointEditAction::Toggle,
10679                    cx,
10680                );
10681            } else {
10682                self.edit_breakpoint_at_anchor(
10683                    anchor,
10684                    Breakpoint::new_standard(),
10685                    BreakpointEditAction::Toggle,
10686                    cx,
10687                );
10688            }
10689        }
10690    }
10691
10692    pub fn edit_breakpoint_at_anchor(
10693        &mut self,
10694        breakpoint_position: Anchor,
10695        breakpoint: Breakpoint,
10696        edit_action: BreakpointEditAction,
10697        cx: &mut Context<Self>,
10698    ) {
10699        let Some(breakpoint_store) = &self.breakpoint_store else {
10700            return;
10701        };
10702
10703        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10704            if breakpoint_position == Anchor::min() {
10705                self.buffer()
10706                    .read(cx)
10707                    .excerpt_buffer_ids()
10708                    .into_iter()
10709                    .next()
10710            } else {
10711                None
10712            }
10713        }) else {
10714            return;
10715        };
10716
10717        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10718            return;
10719        };
10720
10721        breakpoint_store.update(cx, |breakpoint_store, cx| {
10722            breakpoint_store.toggle_breakpoint(
10723                buffer,
10724                BreakpointWithPosition {
10725                    position: breakpoint_position.text_anchor,
10726                    bp: breakpoint,
10727                },
10728                edit_action,
10729                cx,
10730            );
10731        });
10732
10733        cx.notify();
10734    }
10735
10736    #[cfg(any(test, feature = "test-support"))]
10737    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10738        self.breakpoint_store.clone()
10739    }
10740
10741    pub fn prepare_restore_change(
10742        &self,
10743        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10744        hunk: &MultiBufferDiffHunk,
10745        cx: &mut App,
10746    ) -> Option<()> {
10747        if hunk.is_created_file() {
10748            return None;
10749        }
10750        let buffer = self.buffer.read(cx);
10751        let diff = buffer.diff_for(hunk.buffer_id)?;
10752        let buffer = buffer.buffer(hunk.buffer_id)?;
10753        let buffer = buffer.read(cx);
10754        let original_text = diff
10755            .read(cx)
10756            .base_text()
10757            .as_rope()
10758            .slice(hunk.diff_base_byte_range.clone());
10759        let buffer_snapshot = buffer.snapshot();
10760        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10761        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10762            probe
10763                .0
10764                .start
10765                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10766                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10767        }) {
10768            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10769            Some(())
10770        } else {
10771            None
10772        }
10773    }
10774
10775    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10776        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10777    }
10778
10779    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10780        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10781    }
10782
10783    fn manipulate_lines<M>(
10784        &mut self,
10785        window: &mut Window,
10786        cx: &mut Context<Self>,
10787        mut manipulate: M,
10788    ) where
10789        M: FnMut(&str) -> LineManipulationResult,
10790    {
10791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10792
10793        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10794        let buffer = self.buffer.read(cx).snapshot(cx);
10795
10796        let mut edits = Vec::new();
10797
10798        let selections = self.selections.all::<Point>(cx);
10799        let mut selections = selections.iter().peekable();
10800        let mut contiguous_row_selections = Vec::new();
10801        let mut new_selections = Vec::new();
10802        let mut added_lines = 0;
10803        let mut removed_lines = 0;
10804
10805        while let Some(selection) = selections.next() {
10806            let (start_row, end_row) = consume_contiguous_rows(
10807                &mut contiguous_row_selections,
10808                selection,
10809                &display_map,
10810                &mut selections,
10811            );
10812
10813            let start_point = Point::new(start_row.0, 0);
10814            let end_point = Point::new(
10815                end_row.previous_row().0,
10816                buffer.line_len(end_row.previous_row()),
10817            );
10818            let text = buffer
10819                .text_for_range(start_point..end_point)
10820                .collect::<String>();
10821
10822            let LineManipulationResult {
10823                new_text,
10824                line_count_before,
10825                line_count_after,
10826            } = manipulate(&text);
10827
10828            edits.push((start_point..end_point, new_text));
10829
10830            // Selections must change based on added and removed line count
10831            let start_row =
10832                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10833            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10834            new_selections.push(Selection {
10835                id: selection.id,
10836                start: start_row,
10837                end: end_row,
10838                goal: SelectionGoal::None,
10839                reversed: selection.reversed,
10840            });
10841
10842            if line_count_after > line_count_before {
10843                added_lines += line_count_after - line_count_before;
10844            } else if line_count_before > line_count_after {
10845                removed_lines += line_count_before - line_count_after;
10846            }
10847        }
10848
10849        self.transact(window, cx, |this, window, cx| {
10850            let buffer = this.buffer.update(cx, |buffer, cx| {
10851                buffer.edit(edits, None, cx);
10852                buffer.snapshot(cx)
10853            });
10854
10855            // Recalculate offsets on newly edited buffer
10856            let new_selections = new_selections
10857                .iter()
10858                .map(|s| {
10859                    let start_point = Point::new(s.start.0, 0);
10860                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10861                    Selection {
10862                        id: s.id,
10863                        start: buffer.point_to_offset(start_point),
10864                        end: buffer.point_to_offset(end_point),
10865                        goal: s.goal,
10866                        reversed: s.reversed,
10867                    }
10868                })
10869                .collect();
10870
10871            this.change_selections(Default::default(), window, cx, |s| {
10872                s.select(new_selections);
10873            });
10874
10875            this.request_autoscroll(Autoscroll::fit(), cx);
10876        });
10877    }
10878
10879    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10880        self.manipulate_text(window, cx, |text| {
10881            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10882            if has_upper_case_characters {
10883                text.to_lowercase()
10884            } else {
10885                text.to_uppercase()
10886            }
10887        })
10888    }
10889
10890    fn manipulate_immutable_lines<Fn>(
10891        &mut self,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894        mut callback: Fn,
10895    ) where
10896        Fn: FnMut(&mut Vec<&str>),
10897    {
10898        self.manipulate_lines(window, cx, |text| {
10899            let mut lines: Vec<&str> = text.split('\n').collect();
10900            let line_count_before = lines.len();
10901
10902            callback(&mut lines);
10903
10904            LineManipulationResult {
10905                new_text: lines.join("\n"),
10906                line_count_before,
10907                line_count_after: lines.len(),
10908            }
10909        });
10910    }
10911
10912    fn manipulate_mutable_lines<Fn>(
10913        &mut self,
10914        window: &mut Window,
10915        cx: &mut Context<Self>,
10916        mut callback: Fn,
10917    ) where
10918        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10919    {
10920        self.manipulate_lines(window, cx, |text| {
10921            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10922            let line_count_before = lines.len();
10923
10924            callback(&mut lines);
10925
10926            LineManipulationResult {
10927                new_text: lines.join("\n"),
10928                line_count_before,
10929                line_count_after: lines.len(),
10930            }
10931        });
10932    }
10933
10934    pub fn convert_indentation_to_spaces(
10935        &mut self,
10936        _: &ConvertIndentationToSpaces,
10937        window: &mut Window,
10938        cx: &mut Context<Self>,
10939    ) {
10940        let settings = self.buffer.read(cx).language_settings(cx);
10941        let tab_size = settings.tab_size.get() as usize;
10942
10943        self.manipulate_mutable_lines(window, cx, |lines| {
10944            // Allocates a reasonably sized scratch buffer once for the whole loop
10945            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10946            // Avoids recomputing spaces that could be inserted many times
10947            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10948                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10949                .collect();
10950
10951            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10952                let mut chars = line.as_ref().chars();
10953                let mut col = 0;
10954                let mut changed = false;
10955
10956                while let Some(ch) = chars.next() {
10957                    match ch {
10958                        ' ' => {
10959                            reindented_line.push(' ');
10960                            col += 1;
10961                        }
10962                        '\t' => {
10963                            // \t are converted to spaces depending on the current column
10964                            let spaces_len = tab_size - (col % tab_size);
10965                            reindented_line.extend(&space_cache[spaces_len - 1]);
10966                            col += spaces_len;
10967                            changed = true;
10968                        }
10969                        _ => {
10970                            // If we dont append before break, the character is consumed
10971                            reindented_line.push(ch);
10972                            break;
10973                        }
10974                    }
10975                }
10976
10977                if !changed {
10978                    reindented_line.clear();
10979                    continue;
10980                }
10981                // Append the rest of the line and replace old reference with new one
10982                reindented_line.extend(chars);
10983                *line = Cow::Owned(reindented_line.clone());
10984                reindented_line.clear();
10985            }
10986        });
10987    }
10988
10989    pub fn convert_indentation_to_tabs(
10990        &mut self,
10991        _: &ConvertIndentationToTabs,
10992        window: &mut Window,
10993        cx: &mut Context<Self>,
10994    ) {
10995        let settings = self.buffer.read(cx).language_settings(cx);
10996        let tab_size = settings.tab_size.get() as usize;
10997
10998        self.manipulate_mutable_lines(window, cx, |lines| {
10999            // Allocates a reasonably sized buffer once for the whole loop
11000            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11001            // Avoids recomputing spaces that could be inserted many times
11002            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11003                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11004                .collect();
11005
11006            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11007                let mut chars = line.chars();
11008                let mut spaces_count = 0;
11009                let mut first_non_indent_char = None;
11010                let mut changed = false;
11011
11012                while let Some(ch) = chars.next() {
11013                    match ch {
11014                        ' ' => {
11015                            // Keep track of spaces. Append \t when we reach tab_size
11016                            spaces_count += 1;
11017                            changed = true;
11018                            if spaces_count == tab_size {
11019                                reindented_line.push('\t');
11020                                spaces_count = 0;
11021                            }
11022                        }
11023                        '\t' => {
11024                            reindented_line.push('\t');
11025                            spaces_count = 0;
11026                        }
11027                        _ => {
11028                            // Dont append it yet, we might have remaining spaces
11029                            first_non_indent_char = Some(ch);
11030                            break;
11031                        }
11032                    }
11033                }
11034
11035                if !changed {
11036                    reindented_line.clear();
11037                    continue;
11038                }
11039                // Remaining spaces that didn't make a full tab stop
11040                if spaces_count > 0 {
11041                    reindented_line.extend(&space_cache[spaces_count - 1]);
11042                }
11043                // If we consume an extra character that was not indentation, add it back
11044                if let Some(extra_char) = first_non_indent_char {
11045                    reindented_line.push(extra_char);
11046                }
11047                // Append the rest of the line and replace old reference with new one
11048                reindented_line.extend(chars);
11049                *line = Cow::Owned(reindented_line.clone());
11050                reindented_line.clear();
11051            }
11052        });
11053    }
11054
11055    pub fn convert_to_upper_case(
11056        &mut self,
11057        _: &ConvertToUpperCase,
11058        window: &mut Window,
11059        cx: &mut Context<Self>,
11060    ) {
11061        self.manipulate_text(window, cx, |text| text.to_uppercase())
11062    }
11063
11064    pub fn convert_to_lower_case(
11065        &mut self,
11066        _: &ConvertToLowerCase,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) {
11070        self.manipulate_text(window, cx, |text| text.to_lowercase())
11071    }
11072
11073    pub fn convert_to_title_case(
11074        &mut self,
11075        _: &ConvertToTitleCase,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078    ) {
11079        self.manipulate_text(window, cx, |text| {
11080            text.split('\n')
11081                .map(|line| line.to_case(Case::Title))
11082                .join("\n")
11083        })
11084    }
11085
11086    pub fn convert_to_snake_case(
11087        &mut self,
11088        _: &ConvertToSnakeCase,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11093    }
11094
11095    pub fn convert_to_kebab_case(
11096        &mut self,
11097        _: &ConvertToKebabCase,
11098        window: &mut Window,
11099        cx: &mut Context<Self>,
11100    ) {
11101        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11102    }
11103
11104    pub fn convert_to_upper_camel_case(
11105        &mut self,
11106        _: &ConvertToUpperCamelCase,
11107        window: &mut Window,
11108        cx: &mut Context<Self>,
11109    ) {
11110        self.manipulate_text(window, cx, |text| {
11111            text.split('\n')
11112                .map(|line| line.to_case(Case::UpperCamel))
11113                .join("\n")
11114        })
11115    }
11116
11117    pub fn convert_to_lower_camel_case(
11118        &mut self,
11119        _: &ConvertToLowerCamelCase,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11124    }
11125
11126    pub fn convert_to_opposite_case(
11127        &mut self,
11128        _: &ConvertToOppositeCase,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        self.manipulate_text(window, cx, |text| {
11133            text.chars()
11134                .fold(String::with_capacity(text.len()), |mut t, c| {
11135                    if c.is_uppercase() {
11136                        t.extend(c.to_lowercase());
11137                    } else {
11138                        t.extend(c.to_uppercase());
11139                    }
11140                    t
11141                })
11142        })
11143    }
11144
11145    pub fn convert_to_rot13(
11146        &mut self,
11147        _: &ConvertToRot13,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        self.manipulate_text(window, cx, |text| {
11152            text.chars()
11153                .map(|c| match c {
11154                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11155                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11156                    _ => c,
11157                })
11158                .collect()
11159        })
11160    }
11161
11162    pub fn convert_to_rot47(
11163        &mut self,
11164        _: &ConvertToRot47,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        self.manipulate_text(window, cx, |text| {
11169            text.chars()
11170                .map(|c| {
11171                    let code_point = c as u32;
11172                    if code_point >= 33 && code_point <= 126 {
11173                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11174                    }
11175                    c
11176                })
11177                .collect()
11178        })
11179    }
11180
11181    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11182    where
11183        Fn: FnMut(&str) -> String,
11184    {
11185        let buffer = self.buffer.read(cx).snapshot(cx);
11186
11187        let mut new_selections = Vec::new();
11188        let mut edits = Vec::new();
11189        let mut selection_adjustment = 0i32;
11190
11191        for selection in self.selections.all::<usize>(cx) {
11192            let selection_is_empty = selection.is_empty();
11193
11194            let (start, end) = if selection_is_empty {
11195                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11196                (word_range.start, word_range.end)
11197            } else {
11198                (selection.start, selection.end)
11199            };
11200
11201            let text = buffer.text_for_range(start..end).collect::<String>();
11202            let old_length = text.len() as i32;
11203            let text = callback(&text);
11204
11205            new_selections.push(Selection {
11206                start: (start as i32 - selection_adjustment) as usize,
11207                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11208                goal: SelectionGoal::None,
11209                ..selection
11210            });
11211
11212            selection_adjustment += old_length - text.len() as i32;
11213
11214            edits.push((start..end, text));
11215        }
11216
11217        self.transact(window, cx, |this, window, cx| {
11218            this.buffer.update(cx, |buffer, cx| {
11219                buffer.edit(edits, None, cx);
11220            });
11221
11222            this.change_selections(Default::default(), window, cx, |s| {
11223                s.select(new_selections);
11224            });
11225
11226            this.request_autoscroll(Autoscroll::fit(), cx);
11227        });
11228    }
11229
11230    pub fn move_selection_on_drop(
11231        &mut self,
11232        selection: &Selection<Anchor>,
11233        target: DisplayPoint,
11234        is_cut: bool,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11239        let buffer = &display_map.buffer_snapshot;
11240        let mut edits = Vec::new();
11241        let insert_point = display_map
11242            .clip_point(target, Bias::Left)
11243            .to_point(&display_map);
11244        let text = buffer
11245            .text_for_range(selection.start..selection.end)
11246            .collect::<String>();
11247        if is_cut {
11248            edits.push(((selection.start..selection.end), String::new()));
11249        }
11250        let insert_anchor = buffer.anchor_before(insert_point);
11251        edits.push(((insert_anchor..insert_anchor), text));
11252        let last_edit_start = insert_anchor.bias_left(buffer);
11253        let last_edit_end = insert_anchor.bias_right(buffer);
11254        self.transact(window, cx, |this, window, cx| {
11255            this.buffer.update(cx, |buffer, cx| {
11256                buffer.edit(edits, None, cx);
11257            });
11258            this.change_selections(Default::default(), window, cx, |s| {
11259                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11260            });
11261        });
11262    }
11263
11264    pub fn clear_selection_drag_state(&mut self) {
11265        self.selection_drag_state = SelectionDragState::None;
11266    }
11267
11268    pub fn duplicate(
11269        &mut self,
11270        upwards: bool,
11271        whole_lines: bool,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11276
11277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11278        let buffer = &display_map.buffer_snapshot;
11279        let selections = self.selections.all::<Point>(cx);
11280
11281        let mut edits = Vec::new();
11282        let mut selections_iter = selections.iter().peekable();
11283        while let Some(selection) = selections_iter.next() {
11284            let mut rows = selection.spanned_rows(false, &display_map);
11285            // duplicate line-wise
11286            if whole_lines || selection.start == selection.end {
11287                // Avoid duplicating the same lines twice.
11288                while let Some(next_selection) = selections_iter.peek() {
11289                    let next_rows = next_selection.spanned_rows(false, &display_map);
11290                    if next_rows.start < rows.end {
11291                        rows.end = next_rows.end;
11292                        selections_iter.next().unwrap();
11293                    } else {
11294                        break;
11295                    }
11296                }
11297
11298                // Copy the text from the selected row region and splice it either at the start
11299                // or end of the region.
11300                let start = Point::new(rows.start.0, 0);
11301                let end = Point::new(
11302                    rows.end.previous_row().0,
11303                    buffer.line_len(rows.end.previous_row()),
11304                );
11305                let text = buffer
11306                    .text_for_range(start..end)
11307                    .chain(Some("\n"))
11308                    .collect::<String>();
11309                let insert_location = if upwards {
11310                    Point::new(rows.end.0, 0)
11311                } else {
11312                    start
11313                };
11314                edits.push((insert_location..insert_location, text));
11315            } else {
11316                // duplicate character-wise
11317                let start = selection.start;
11318                let end = selection.end;
11319                let text = buffer.text_for_range(start..end).collect::<String>();
11320                edits.push((selection.end..selection.end, text));
11321            }
11322        }
11323
11324        self.transact(window, cx, |this, _, cx| {
11325            this.buffer.update(cx, |buffer, cx| {
11326                buffer.edit(edits, None, cx);
11327            });
11328
11329            this.request_autoscroll(Autoscroll::fit(), cx);
11330        });
11331    }
11332
11333    pub fn duplicate_line_up(
11334        &mut self,
11335        _: &DuplicateLineUp,
11336        window: &mut Window,
11337        cx: &mut Context<Self>,
11338    ) {
11339        self.duplicate(true, true, window, cx);
11340    }
11341
11342    pub fn duplicate_line_down(
11343        &mut self,
11344        _: &DuplicateLineDown,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        self.duplicate(false, true, window, cx);
11349    }
11350
11351    pub fn duplicate_selection(
11352        &mut self,
11353        _: &DuplicateSelection,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        self.duplicate(false, false, window, cx);
11358    }
11359
11360    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11362        if self.mode.is_single_line() {
11363            cx.propagate();
11364            return;
11365        }
11366
11367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11368        let buffer = self.buffer.read(cx).snapshot(cx);
11369
11370        let mut edits = Vec::new();
11371        let mut unfold_ranges = Vec::new();
11372        let mut refold_creases = Vec::new();
11373
11374        let selections = self.selections.all::<Point>(cx);
11375        let mut selections = selections.iter().peekable();
11376        let mut contiguous_row_selections = Vec::new();
11377        let mut new_selections = Vec::new();
11378
11379        while let Some(selection) = selections.next() {
11380            // Find all the selections that span a contiguous row range
11381            let (start_row, end_row) = consume_contiguous_rows(
11382                &mut contiguous_row_selections,
11383                selection,
11384                &display_map,
11385                &mut selections,
11386            );
11387
11388            // Move the text spanned by the row range to be before the line preceding the row range
11389            if start_row.0 > 0 {
11390                let range_to_move = Point::new(
11391                    start_row.previous_row().0,
11392                    buffer.line_len(start_row.previous_row()),
11393                )
11394                    ..Point::new(
11395                        end_row.previous_row().0,
11396                        buffer.line_len(end_row.previous_row()),
11397                    );
11398                let insertion_point = display_map
11399                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11400                    .0;
11401
11402                // Don't move lines across excerpts
11403                if buffer
11404                    .excerpt_containing(insertion_point..range_to_move.end)
11405                    .is_some()
11406                {
11407                    let text = buffer
11408                        .text_for_range(range_to_move.clone())
11409                        .flat_map(|s| s.chars())
11410                        .skip(1)
11411                        .chain(['\n'])
11412                        .collect::<String>();
11413
11414                    edits.push((
11415                        buffer.anchor_after(range_to_move.start)
11416                            ..buffer.anchor_before(range_to_move.end),
11417                        String::new(),
11418                    ));
11419                    let insertion_anchor = buffer.anchor_after(insertion_point);
11420                    edits.push((insertion_anchor..insertion_anchor, text));
11421
11422                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11423
11424                    // Move selections up
11425                    new_selections.extend(contiguous_row_selections.drain(..).map(
11426                        |mut selection| {
11427                            selection.start.row -= row_delta;
11428                            selection.end.row -= row_delta;
11429                            selection
11430                        },
11431                    ));
11432
11433                    // Move folds up
11434                    unfold_ranges.push(range_to_move.clone());
11435                    for fold in display_map.folds_in_range(
11436                        buffer.anchor_before(range_to_move.start)
11437                            ..buffer.anchor_after(range_to_move.end),
11438                    ) {
11439                        let mut start = fold.range.start.to_point(&buffer);
11440                        let mut end = fold.range.end.to_point(&buffer);
11441                        start.row -= row_delta;
11442                        end.row -= row_delta;
11443                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11444                    }
11445                }
11446            }
11447
11448            // If we didn't move line(s), preserve the existing selections
11449            new_selections.append(&mut contiguous_row_selections);
11450        }
11451
11452        self.transact(window, cx, |this, window, cx| {
11453            this.unfold_ranges(&unfold_ranges, true, true, cx);
11454            this.buffer.update(cx, |buffer, cx| {
11455                for (range, text) in edits {
11456                    buffer.edit([(range, text)], None, cx);
11457                }
11458            });
11459            this.fold_creases(refold_creases, true, window, cx);
11460            this.change_selections(Default::default(), window, cx, |s| {
11461                s.select(new_selections);
11462            })
11463        });
11464    }
11465
11466    pub fn move_line_down(
11467        &mut self,
11468        _: &MoveLineDown,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11473        if self.mode.is_single_line() {
11474            cx.propagate();
11475            return;
11476        }
11477
11478        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11479        let buffer = self.buffer.read(cx).snapshot(cx);
11480
11481        let mut edits = Vec::new();
11482        let mut unfold_ranges = Vec::new();
11483        let mut refold_creases = Vec::new();
11484
11485        let selections = self.selections.all::<Point>(cx);
11486        let mut selections = selections.iter().peekable();
11487        let mut contiguous_row_selections = Vec::new();
11488        let mut new_selections = Vec::new();
11489
11490        while let Some(selection) = selections.next() {
11491            // Find all the selections that span a contiguous row range
11492            let (start_row, end_row) = consume_contiguous_rows(
11493                &mut contiguous_row_selections,
11494                selection,
11495                &display_map,
11496                &mut selections,
11497            );
11498
11499            // Move the text spanned by the row range to be after the last line of the row range
11500            if end_row.0 <= buffer.max_point().row {
11501                let range_to_move =
11502                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11503                let insertion_point = display_map
11504                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11505                    .0;
11506
11507                // Don't move lines across excerpt boundaries
11508                if buffer
11509                    .excerpt_containing(range_to_move.start..insertion_point)
11510                    .is_some()
11511                {
11512                    let mut text = String::from("\n");
11513                    text.extend(buffer.text_for_range(range_to_move.clone()));
11514                    text.pop(); // Drop trailing newline
11515                    edits.push((
11516                        buffer.anchor_after(range_to_move.start)
11517                            ..buffer.anchor_before(range_to_move.end),
11518                        String::new(),
11519                    ));
11520                    let insertion_anchor = buffer.anchor_after(insertion_point);
11521                    edits.push((insertion_anchor..insertion_anchor, text));
11522
11523                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11524
11525                    // Move selections down
11526                    new_selections.extend(contiguous_row_selections.drain(..).map(
11527                        |mut selection| {
11528                            selection.start.row += row_delta;
11529                            selection.end.row += row_delta;
11530                            selection
11531                        },
11532                    ));
11533
11534                    // Move folds down
11535                    unfold_ranges.push(range_to_move.clone());
11536                    for fold in display_map.folds_in_range(
11537                        buffer.anchor_before(range_to_move.start)
11538                            ..buffer.anchor_after(range_to_move.end),
11539                    ) {
11540                        let mut start = fold.range.start.to_point(&buffer);
11541                        let mut end = fold.range.end.to_point(&buffer);
11542                        start.row += row_delta;
11543                        end.row += row_delta;
11544                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11545                    }
11546                }
11547            }
11548
11549            // If we didn't move line(s), preserve the existing selections
11550            new_selections.append(&mut contiguous_row_selections);
11551        }
11552
11553        self.transact(window, cx, |this, window, cx| {
11554            this.unfold_ranges(&unfold_ranges, true, true, cx);
11555            this.buffer.update(cx, |buffer, cx| {
11556                for (range, text) in edits {
11557                    buffer.edit([(range, text)], None, cx);
11558                }
11559            });
11560            this.fold_creases(refold_creases, true, window, cx);
11561            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11562        });
11563    }
11564
11565    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11567        let text_layout_details = &self.text_layout_details(window);
11568        self.transact(window, cx, |this, window, cx| {
11569            let edits = this.change_selections(Default::default(), window, cx, |s| {
11570                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11571                s.move_with(|display_map, selection| {
11572                    if !selection.is_empty() {
11573                        return;
11574                    }
11575
11576                    let mut head = selection.head();
11577                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11578                    if head.column() == display_map.line_len(head.row()) {
11579                        transpose_offset = display_map
11580                            .buffer_snapshot
11581                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11582                    }
11583
11584                    if transpose_offset == 0 {
11585                        return;
11586                    }
11587
11588                    *head.column_mut() += 1;
11589                    head = display_map.clip_point(head, Bias::Right);
11590                    let goal = SelectionGoal::HorizontalPosition(
11591                        display_map
11592                            .x_for_display_point(head, text_layout_details)
11593                            .into(),
11594                    );
11595                    selection.collapse_to(head, goal);
11596
11597                    let transpose_start = display_map
11598                        .buffer_snapshot
11599                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11600                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11601                        let transpose_end = display_map
11602                            .buffer_snapshot
11603                            .clip_offset(transpose_offset + 1, Bias::Right);
11604                        if let Some(ch) =
11605                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11606                        {
11607                            edits.push((transpose_start..transpose_offset, String::new()));
11608                            edits.push((transpose_end..transpose_end, ch.to_string()));
11609                        }
11610                    }
11611                });
11612                edits
11613            });
11614            this.buffer
11615                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11616            let selections = this.selections.all::<usize>(cx);
11617            this.change_selections(Default::default(), window, cx, |s| {
11618                s.select(selections);
11619            });
11620        });
11621    }
11622
11623    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11624        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11625        if self.mode.is_single_line() {
11626            cx.propagate();
11627            return;
11628        }
11629
11630        self.rewrap_impl(RewrapOptions::default(), cx)
11631    }
11632
11633    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11634        let buffer = self.buffer.read(cx).snapshot(cx);
11635        let selections = self.selections.all::<Point>(cx);
11636
11637        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11638        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11639            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11640                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11641                .peekable();
11642
11643            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11644                row
11645            } else {
11646                return Vec::new();
11647            };
11648
11649            let language_settings = buffer.language_settings_at(selection.head(), cx);
11650            let language_scope = buffer.language_scope_at(selection.head());
11651
11652            let indent_and_prefix_for_row =
11653                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11654                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11655                    let (comment_prefix, rewrap_prefix) =
11656                        if let Some(language_scope) = &language_scope {
11657                            let indent_end = Point::new(row, indent.len);
11658                            let comment_prefix = language_scope
11659                                .line_comment_prefixes()
11660                                .iter()
11661                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11662                                .map(|prefix| prefix.to_string());
11663                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11664                            let line_text_after_indent = buffer
11665                                .text_for_range(indent_end..line_end)
11666                                .collect::<String>();
11667                            let rewrap_prefix = language_scope
11668                                .rewrap_prefixes()
11669                                .iter()
11670                                .find_map(|prefix_regex| {
11671                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11672                                        if mat.start() == 0 {
11673                                            Some(mat.as_str().to_string())
11674                                        } else {
11675                                            None
11676                                        }
11677                                    })
11678                                })
11679                                .flatten();
11680                            (comment_prefix, rewrap_prefix)
11681                        } else {
11682                            (None, None)
11683                        };
11684                    (indent, comment_prefix, rewrap_prefix)
11685                };
11686
11687            let mut ranges = Vec::new();
11688            let from_empty_selection = selection.is_empty();
11689
11690            let mut current_range_start = first_row;
11691            let mut prev_row = first_row;
11692            let (
11693                mut current_range_indent,
11694                mut current_range_comment_prefix,
11695                mut current_range_rewrap_prefix,
11696            ) = indent_and_prefix_for_row(first_row);
11697
11698            for row in non_blank_rows_iter.skip(1) {
11699                let has_paragraph_break = row > prev_row + 1;
11700
11701                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11702                    indent_and_prefix_for_row(row);
11703
11704                let has_indent_change = row_indent != current_range_indent;
11705                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11706
11707                let has_boundary_change = has_comment_change
11708                    || row_rewrap_prefix.is_some()
11709                    || (has_indent_change && current_range_comment_prefix.is_some());
11710
11711                if has_paragraph_break || has_boundary_change {
11712                    ranges.push((
11713                        language_settings.clone(),
11714                        Point::new(current_range_start, 0)
11715                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11716                        current_range_indent,
11717                        current_range_comment_prefix.clone(),
11718                        current_range_rewrap_prefix.clone(),
11719                        from_empty_selection,
11720                    ));
11721                    current_range_start = row;
11722                    current_range_indent = row_indent;
11723                    current_range_comment_prefix = row_comment_prefix;
11724                    current_range_rewrap_prefix = row_rewrap_prefix;
11725                }
11726                prev_row = row;
11727            }
11728
11729            ranges.push((
11730                language_settings.clone(),
11731                Point::new(current_range_start, 0)
11732                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11733                current_range_indent,
11734                current_range_comment_prefix,
11735                current_range_rewrap_prefix,
11736                from_empty_selection,
11737            ));
11738
11739            ranges
11740        });
11741
11742        let mut edits = Vec::new();
11743        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11744
11745        for (
11746            language_settings,
11747            wrap_range,
11748            indent_size,
11749            comment_prefix,
11750            rewrap_prefix,
11751            from_empty_selection,
11752        ) in wrap_ranges
11753        {
11754            let mut start_row = wrap_range.start.row;
11755            let mut end_row = wrap_range.end.row;
11756
11757            // Skip selections that overlap with a range that has already been rewrapped.
11758            let selection_range = start_row..end_row;
11759            if rewrapped_row_ranges
11760                .iter()
11761                .any(|range| range.overlaps(&selection_range))
11762            {
11763                continue;
11764            }
11765
11766            let tab_size = language_settings.tab_size;
11767
11768            let indent_prefix = indent_size.chars().collect::<String>();
11769            let mut line_prefix = indent_prefix.clone();
11770            let mut inside_comment = false;
11771            if let Some(prefix) = &comment_prefix {
11772                line_prefix.push_str(prefix);
11773                inside_comment = true;
11774            }
11775            if let Some(prefix) = &rewrap_prefix {
11776                line_prefix.push_str(prefix);
11777            }
11778
11779            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11780                RewrapBehavior::InComments => inside_comment,
11781                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11782                RewrapBehavior::Anywhere => true,
11783            };
11784
11785            let should_rewrap = options.override_language_settings
11786                || allow_rewrap_based_on_language
11787                || self.hard_wrap.is_some();
11788            if !should_rewrap {
11789                continue;
11790            }
11791
11792            if from_empty_selection {
11793                'expand_upwards: while start_row > 0 {
11794                    let prev_row = start_row - 1;
11795                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11796                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11797                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11798                    {
11799                        start_row = prev_row;
11800                    } else {
11801                        break 'expand_upwards;
11802                    }
11803                }
11804
11805                'expand_downwards: while end_row < buffer.max_point().row {
11806                    let next_row = end_row + 1;
11807                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11808                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11809                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11810                    {
11811                        end_row = next_row;
11812                    } else {
11813                        break 'expand_downwards;
11814                    }
11815                }
11816            }
11817
11818            let start = Point::new(start_row, 0);
11819            let start_offset = start.to_offset(&buffer);
11820            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11821            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11822            let Some(lines_without_prefixes) = selection_text
11823                .lines()
11824                .enumerate()
11825                .map(|(ix, line)| {
11826                    let line_trimmed = line.trim_start();
11827                    if rewrap_prefix.is_some() && ix > 0 {
11828                        Ok(line_trimmed)
11829                    } else {
11830                        line_trimmed
11831                            .strip_prefix(&line_prefix.trim_start())
11832                            .with_context(|| {
11833                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11834                            })
11835                    }
11836                })
11837                .collect::<Result<Vec<_>, _>>()
11838                .log_err()
11839            else {
11840                continue;
11841            };
11842
11843            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11844                buffer
11845                    .language_settings_at(Point::new(start_row, 0), cx)
11846                    .preferred_line_length as usize
11847            });
11848
11849            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11850                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11851            } else {
11852                line_prefix.clone()
11853            };
11854
11855            let wrapped_text = wrap_with_prefix(
11856                line_prefix,
11857                subsequent_lines_prefix,
11858                lines_without_prefixes.join("\n"),
11859                wrap_column,
11860                tab_size,
11861                options.preserve_existing_whitespace,
11862            );
11863
11864            // TODO: should always use char-based diff while still supporting cursor behavior that
11865            // matches vim.
11866            let mut diff_options = DiffOptions::default();
11867            if options.override_language_settings {
11868                diff_options.max_word_diff_len = 0;
11869                diff_options.max_word_diff_line_count = 0;
11870            } else {
11871                diff_options.max_word_diff_len = usize::MAX;
11872                diff_options.max_word_diff_line_count = usize::MAX;
11873            }
11874
11875            for (old_range, new_text) in
11876                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11877            {
11878                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11879                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11880                edits.push((edit_start..edit_end, new_text));
11881            }
11882
11883            rewrapped_row_ranges.push(start_row..=end_row);
11884        }
11885
11886        self.buffer
11887            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11888    }
11889
11890    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11891        let mut text = String::new();
11892        let buffer = self.buffer.read(cx).snapshot(cx);
11893        let mut selections = self.selections.all::<Point>(cx);
11894        let mut clipboard_selections = Vec::with_capacity(selections.len());
11895        {
11896            let max_point = buffer.max_point();
11897            let mut is_first = true;
11898            for selection in &mut selections {
11899                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11900                if is_entire_line {
11901                    selection.start = Point::new(selection.start.row, 0);
11902                    if !selection.is_empty() && selection.end.column == 0 {
11903                        selection.end = cmp::min(max_point, selection.end);
11904                    } else {
11905                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11906                    }
11907                    selection.goal = SelectionGoal::None;
11908                }
11909                if is_first {
11910                    is_first = false;
11911                } else {
11912                    text += "\n";
11913                }
11914                let mut len = 0;
11915                for chunk in buffer.text_for_range(selection.start..selection.end) {
11916                    text.push_str(chunk);
11917                    len += chunk.len();
11918                }
11919                clipboard_selections.push(ClipboardSelection {
11920                    len,
11921                    is_entire_line,
11922                    first_line_indent: buffer
11923                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11924                        .len,
11925                });
11926            }
11927        }
11928
11929        self.transact(window, cx, |this, window, cx| {
11930            this.change_selections(Default::default(), window, cx, |s| {
11931                s.select(selections);
11932            });
11933            this.insert("", window, cx);
11934        });
11935        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11936    }
11937
11938    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11940        let item = self.cut_common(window, cx);
11941        cx.write_to_clipboard(item);
11942    }
11943
11944    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11946        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11947            s.move_with(|snapshot, sel| {
11948                if sel.is_empty() {
11949                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11950                }
11951            });
11952        });
11953        let item = self.cut_common(window, cx);
11954        cx.set_global(KillRing(item))
11955    }
11956
11957    pub fn kill_ring_yank(
11958        &mut self,
11959        _: &KillRingYank,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962    ) {
11963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11964        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11965            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11966                (kill_ring.text().to_string(), kill_ring.metadata_json())
11967            } else {
11968                return;
11969            }
11970        } else {
11971            return;
11972        };
11973        self.do_paste(&text, metadata, false, window, cx);
11974    }
11975
11976    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11977        self.do_copy(true, cx);
11978    }
11979
11980    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11981        self.do_copy(false, cx);
11982    }
11983
11984    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11985        let selections = self.selections.all::<Point>(cx);
11986        let buffer = self.buffer.read(cx).read(cx);
11987        let mut text = String::new();
11988
11989        let mut clipboard_selections = Vec::with_capacity(selections.len());
11990        {
11991            let max_point = buffer.max_point();
11992            let mut is_first = true;
11993            for selection in &selections {
11994                let mut start = selection.start;
11995                let mut end = selection.end;
11996                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11997                if is_entire_line {
11998                    start = Point::new(start.row, 0);
11999                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12000                }
12001
12002                let mut trimmed_selections = Vec::new();
12003                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12004                    let row = MultiBufferRow(start.row);
12005                    let first_indent = buffer.indent_size_for_line(row);
12006                    if first_indent.len == 0 || start.column > first_indent.len {
12007                        trimmed_selections.push(start..end);
12008                    } else {
12009                        trimmed_selections.push(
12010                            Point::new(row.0, first_indent.len)
12011                                ..Point::new(row.0, buffer.line_len(row)),
12012                        );
12013                        for row in start.row + 1..=end.row {
12014                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12015                            if row == end.row {
12016                                line_len = end.column;
12017                            }
12018                            if line_len == 0 {
12019                                trimmed_selections
12020                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12021                                continue;
12022                            }
12023                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12024                            if row_indent_size.len >= first_indent.len {
12025                                trimmed_selections.push(
12026                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12027                                );
12028                            } else {
12029                                trimmed_selections.clear();
12030                                trimmed_selections.push(start..end);
12031                                break;
12032                            }
12033                        }
12034                    }
12035                } else {
12036                    trimmed_selections.push(start..end);
12037                }
12038
12039                for trimmed_range in trimmed_selections {
12040                    if is_first {
12041                        is_first = false;
12042                    } else {
12043                        text += "\n";
12044                    }
12045                    let mut len = 0;
12046                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12047                        text.push_str(chunk);
12048                        len += chunk.len();
12049                    }
12050                    clipboard_selections.push(ClipboardSelection {
12051                        len,
12052                        is_entire_line,
12053                        first_line_indent: buffer
12054                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12055                            .len,
12056                    });
12057                }
12058            }
12059        }
12060
12061        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12062            text,
12063            clipboard_selections,
12064        ));
12065    }
12066
12067    pub fn do_paste(
12068        &mut self,
12069        text: &String,
12070        clipboard_selections: Option<Vec<ClipboardSelection>>,
12071        handle_entire_lines: bool,
12072        window: &mut Window,
12073        cx: &mut Context<Self>,
12074    ) {
12075        if self.read_only(cx) {
12076            return;
12077        }
12078
12079        let clipboard_text = Cow::Borrowed(text);
12080
12081        self.transact(window, cx, |this, window, cx| {
12082            if let Some(mut clipboard_selections) = clipboard_selections {
12083                let old_selections = this.selections.all::<usize>(cx);
12084                let all_selections_were_entire_line =
12085                    clipboard_selections.iter().all(|s| s.is_entire_line);
12086                let first_selection_indent_column =
12087                    clipboard_selections.first().map(|s| s.first_line_indent);
12088                if clipboard_selections.len() != old_selections.len() {
12089                    clipboard_selections.drain(..);
12090                }
12091                let cursor_offset = this.selections.last::<usize>(cx).head();
12092                let mut auto_indent_on_paste = true;
12093
12094                this.buffer.update(cx, |buffer, cx| {
12095                    let snapshot = buffer.read(cx);
12096                    auto_indent_on_paste = snapshot
12097                        .language_settings_at(cursor_offset, cx)
12098                        .auto_indent_on_paste;
12099
12100                    let mut start_offset = 0;
12101                    let mut edits = Vec::new();
12102                    let mut original_indent_columns = Vec::new();
12103                    for (ix, selection) in old_selections.iter().enumerate() {
12104                        let to_insert;
12105                        let entire_line;
12106                        let original_indent_column;
12107                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12108                            let end_offset = start_offset + clipboard_selection.len;
12109                            to_insert = &clipboard_text[start_offset..end_offset];
12110                            entire_line = clipboard_selection.is_entire_line;
12111                            start_offset = end_offset + 1;
12112                            original_indent_column = Some(clipboard_selection.first_line_indent);
12113                        } else {
12114                            to_insert = clipboard_text.as_str();
12115                            entire_line = all_selections_were_entire_line;
12116                            original_indent_column = first_selection_indent_column
12117                        }
12118
12119                        // If the corresponding selection was empty when this slice of the
12120                        // clipboard text was written, then the entire line containing the
12121                        // selection was copied. If this selection is also currently empty,
12122                        // then paste the line before the current line of the buffer.
12123                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12124                            let column = selection.start.to_point(&snapshot).column as usize;
12125                            let line_start = selection.start - column;
12126                            line_start..line_start
12127                        } else {
12128                            selection.range()
12129                        };
12130
12131                        edits.push((range, to_insert));
12132                        original_indent_columns.push(original_indent_column);
12133                    }
12134                    drop(snapshot);
12135
12136                    buffer.edit(
12137                        edits,
12138                        if auto_indent_on_paste {
12139                            Some(AutoindentMode::Block {
12140                                original_indent_columns,
12141                            })
12142                        } else {
12143                            None
12144                        },
12145                        cx,
12146                    );
12147                });
12148
12149                let selections = this.selections.all::<usize>(cx);
12150                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12151            } else {
12152                this.insert(&clipboard_text, window, cx);
12153            }
12154        });
12155    }
12156
12157    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12159        if let Some(item) = cx.read_from_clipboard() {
12160            let entries = item.entries();
12161
12162            match entries.first() {
12163                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12164                // of all the pasted entries.
12165                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12166                    .do_paste(
12167                        clipboard_string.text(),
12168                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12169                        true,
12170                        window,
12171                        cx,
12172                    ),
12173                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12174            }
12175        }
12176    }
12177
12178    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12179        if self.read_only(cx) {
12180            return;
12181        }
12182
12183        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12184
12185        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12186            if let Some((selections, _)) =
12187                self.selection_history.transaction(transaction_id).cloned()
12188            {
12189                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12190                    s.select_anchors(selections.to_vec());
12191                });
12192            } else {
12193                log::error!(
12194                    "No entry in selection_history found for undo. \
12195                     This may correspond to a bug where undo does not update the selection. \
12196                     If this is occurring, please add details to \
12197                     https://github.com/zed-industries/zed/issues/22692"
12198                );
12199            }
12200            self.request_autoscroll(Autoscroll::fit(), cx);
12201            self.unmark_text(window, cx);
12202            self.refresh_inline_completion(true, false, window, cx);
12203            cx.emit(EditorEvent::Edited { transaction_id });
12204            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12205        }
12206    }
12207
12208    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12209        if self.read_only(cx) {
12210            return;
12211        }
12212
12213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12214
12215        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12216            if let Some((_, Some(selections))) =
12217                self.selection_history.transaction(transaction_id).cloned()
12218            {
12219                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12220                    s.select_anchors(selections.to_vec());
12221                });
12222            } else {
12223                log::error!(
12224                    "No entry in selection_history found for redo. \
12225                     This may correspond to a bug where undo does not update the selection. \
12226                     If this is occurring, please add details to \
12227                     https://github.com/zed-industries/zed/issues/22692"
12228                );
12229            }
12230            self.request_autoscroll(Autoscroll::fit(), cx);
12231            self.unmark_text(window, cx);
12232            self.refresh_inline_completion(true, false, window, cx);
12233            cx.emit(EditorEvent::Edited { transaction_id });
12234        }
12235    }
12236
12237    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12238        self.buffer
12239            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12240    }
12241
12242    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12243        self.buffer
12244            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12245    }
12246
12247    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12249        self.change_selections(Default::default(), window, cx, |s| {
12250            s.move_with(|map, selection| {
12251                let cursor = if selection.is_empty() {
12252                    movement::left(map, selection.start)
12253                } else {
12254                    selection.start
12255                };
12256                selection.collapse_to(cursor, SelectionGoal::None);
12257            });
12258        })
12259    }
12260
12261    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12263        self.change_selections(Default::default(), window, cx, |s| {
12264            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12265        })
12266    }
12267
12268    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12270        self.change_selections(Default::default(), window, cx, |s| {
12271            s.move_with(|map, selection| {
12272                let cursor = if selection.is_empty() {
12273                    movement::right(map, selection.end)
12274                } else {
12275                    selection.end
12276                };
12277                selection.collapse_to(cursor, SelectionGoal::None)
12278            });
12279        })
12280    }
12281
12282    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12284        self.change_selections(Default::default(), window, cx, |s| {
12285            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12286        })
12287    }
12288
12289    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12290        if self.take_rename(true, window, cx).is_some() {
12291            return;
12292        }
12293
12294        if self.mode.is_single_line() {
12295            cx.propagate();
12296            return;
12297        }
12298
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12300
12301        let text_layout_details = &self.text_layout_details(window);
12302        let selection_count = self.selections.count();
12303        let first_selection = self.selections.first_anchor();
12304
12305        self.change_selections(Default::default(), window, cx, |s| {
12306            s.move_with(|map, selection| {
12307                if !selection.is_empty() {
12308                    selection.goal = SelectionGoal::None;
12309                }
12310                let (cursor, goal) = movement::up(
12311                    map,
12312                    selection.start,
12313                    selection.goal,
12314                    false,
12315                    text_layout_details,
12316                );
12317                selection.collapse_to(cursor, goal);
12318            });
12319        });
12320
12321        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12322        {
12323            cx.propagate();
12324        }
12325    }
12326
12327    pub fn move_up_by_lines(
12328        &mut self,
12329        action: &MoveUpByLines,
12330        window: &mut Window,
12331        cx: &mut Context<Self>,
12332    ) {
12333        if self.take_rename(true, window, cx).is_some() {
12334            return;
12335        }
12336
12337        if self.mode.is_single_line() {
12338            cx.propagate();
12339            return;
12340        }
12341
12342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12343
12344        let text_layout_details = &self.text_layout_details(window);
12345
12346        self.change_selections(Default::default(), window, cx, |s| {
12347            s.move_with(|map, selection| {
12348                if !selection.is_empty() {
12349                    selection.goal = SelectionGoal::None;
12350                }
12351                let (cursor, goal) = movement::up_by_rows(
12352                    map,
12353                    selection.start,
12354                    action.lines,
12355                    selection.goal,
12356                    false,
12357                    text_layout_details,
12358                );
12359                selection.collapse_to(cursor, goal);
12360            });
12361        })
12362    }
12363
12364    pub fn move_down_by_lines(
12365        &mut self,
12366        action: &MoveDownByLines,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        if self.take_rename(true, window, cx).is_some() {
12371            return;
12372        }
12373
12374        if self.mode.is_single_line() {
12375            cx.propagate();
12376            return;
12377        }
12378
12379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12380
12381        let text_layout_details = &self.text_layout_details(window);
12382
12383        self.change_selections(Default::default(), window, cx, |s| {
12384            s.move_with(|map, selection| {
12385                if !selection.is_empty() {
12386                    selection.goal = SelectionGoal::None;
12387                }
12388                let (cursor, goal) = movement::down_by_rows(
12389                    map,
12390                    selection.start,
12391                    action.lines,
12392                    selection.goal,
12393                    false,
12394                    text_layout_details,
12395                );
12396                selection.collapse_to(cursor, goal);
12397            });
12398        })
12399    }
12400
12401    pub fn select_down_by_lines(
12402        &mut self,
12403        action: &SelectDownByLines,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12408        let text_layout_details = &self.text_layout_details(window);
12409        self.change_selections(Default::default(), window, cx, |s| {
12410            s.move_heads_with(|map, head, goal| {
12411                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12412            })
12413        })
12414    }
12415
12416    pub fn select_up_by_lines(
12417        &mut self,
12418        action: &SelectUpByLines,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12423        let text_layout_details = &self.text_layout_details(window);
12424        self.change_selections(Default::default(), window, cx, |s| {
12425            s.move_heads_with(|map, head, goal| {
12426                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12427            })
12428        })
12429    }
12430
12431    pub fn select_page_up(
12432        &mut self,
12433        _: &SelectPageUp,
12434        window: &mut Window,
12435        cx: &mut Context<Self>,
12436    ) {
12437        let Some(row_count) = self.visible_row_count() else {
12438            return;
12439        };
12440
12441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12442
12443        let text_layout_details = &self.text_layout_details(window);
12444
12445        self.change_selections(Default::default(), window, cx, |s| {
12446            s.move_heads_with(|map, head, goal| {
12447                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12448            })
12449        })
12450    }
12451
12452    pub fn move_page_up(
12453        &mut self,
12454        action: &MovePageUp,
12455        window: &mut Window,
12456        cx: &mut Context<Self>,
12457    ) {
12458        if self.take_rename(true, window, cx).is_some() {
12459            return;
12460        }
12461
12462        if self
12463            .context_menu
12464            .borrow_mut()
12465            .as_mut()
12466            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12467            .unwrap_or(false)
12468        {
12469            return;
12470        }
12471
12472        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12473            cx.propagate();
12474            return;
12475        }
12476
12477        let Some(row_count) = self.visible_row_count() else {
12478            return;
12479        };
12480
12481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12482
12483        let effects = if action.center_cursor {
12484            SelectionEffects::scroll(Autoscroll::center())
12485        } else {
12486            SelectionEffects::default()
12487        };
12488
12489        let text_layout_details = &self.text_layout_details(window);
12490
12491        self.change_selections(effects, window, cx, |s| {
12492            s.move_with(|map, selection| {
12493                if !selection.is_empty() {
12494                    selection.goal = SelectionGoal::None;
12495                }
12496                let (cursor, goal) = movement::up_by_rows(
12497                    map,
12498                    selection.end,
12499                    row_count,
12500                    selection.goal,
12501                    false,
12502                    text_layout_details,
12503                );
12504                selection.collapse_to(cursor, goal);
12505            });
12506        });
12507    }
12508
12509    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12511        let text_layout_details = &self.text_layout_details(window);
12512        self.change_selections(Default::default(), window, cx, |s| {
12513            s.move_heads_with(|map, head, goal| {
12514                movement::up(map, head, goal, false, text_layout_details)
12515            })
12516        })
12517    }
12518
12519    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12520        self.take_rename(true, window, cx);
12521
12522        if self.mode.is_single_line() {
12523            cx.propagate();
12524            return;
12525        }
12526
12527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12528
12529        let text_layout_details = &self.text_layout_details(window);
12530        let selection_count = self.selections.count();
12531        let first_selection = self.selections.first_anchor();
12532
12533        self.change_selections(Default::default(), window, cx, |s| {
12534            s.move_with(|map, selection| {
12535                if !selection.is_empty() {
12536                    selection.goal = SelectionGoal::None;
12537                }
12538                let (cursor, goal) = movement::down(
12539                    map,
12540                    selection.end,
12541                    selection.goal,
12542                    false,
12543                    text_layout_details,
12544                );
12545                selection.collapse_to(cursor, goal);
12546            });
12547        });
12548
12549        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12550        {
12551            cx.propagate();
12552        }
12553    }
12554
12555    pub fn select_page_down(
12556        &mut self,
12557        _: &SelectPageDown,
12558        window: &mut Window,
12559        cx: &mut Context<Self>,
12560    ) {
12561        let Some(row_count) = self.visible_row_count() else {
12562            return;
12563        };
12564
12565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12566
12567        let text_layout_details = &self.text_layout_details(window);
12568
12569        self.change_selections(Default::default(), window, cx, |s| {
12570            s.move_heads_with(|map, head, goal| {
12571                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12572            })
12573        })
12574    }
12575
12576    pub fn move_page_down(
12577        &mut self,
12578        action: &MovePageDown,
12579        window: &mut Window,
12580        cx: &mut Context<Self>,
12581    ) {
12582        if self.take_rename(true, window, cx).is_some() {
12583            return;
12584        }
12585
12586        if self
12587            .context_menu
12588            .borrow_mut()
12589            .as_mut()
12590            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12591            .unwrap_or(false)
12592        {
12593            return;
12594        }
12595
12596        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12597            cx.propagate();
12598            return;
12599        }
12600
12601        let Some(row_count) = self.visible_row_count() else {
12602            return;
12603        };
12604
12605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12606
12607        let effects = if action.center_cursor {
12608            SelectionEffects::scroll(Autoscroll::center())
12609        } else {
12610            SelectionEffects::default()
12611        };
12612
12613        let text_layout_details = &self.text_layout_details(window);
12614        self.change_selections(effects, window, cx, |s| {
12615            s.move_with(|map, selection| {
12616                if !selection.is_empty() {
12617                    selection.goal = SelectionGoal::None;
12618                }
12619                let (cursor, goal) = movement::down_by_rows(
12620                    map,
12621                    selection.end,
12622                    row_count,
12623                    selection.goal,
12624                    false,
12625                    text_layout_details,
12626                );
12627                selection.collapse_to(cursor, goal);
12628            });
12629        });
12630    }
12631
12632    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12634        let text_layout_details = &self.text_layout_details(window);
12635        self.change_selections(Default::default(), window, cx, |s| {
12636            s.move_heads_with(|map, head, goal| {
12637                movement::down(map, head, goal, false, text_layout_details)
12638            })
12639        });
12640    }
12641
12642    pub fn context_menu_first(
12643        &mut self,
12644        _: &ContextMenuFirst,
12645        window: &mut Window,
12646        cx: &mut Context<Self>,
12647    ) {
12648        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12649            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12650        }
12651    }
12652
12653    pub fn context_menu_prev(
12654        &mut self,
12655        _: &ContextMenuPrevious,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) {
12659        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12660            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12661        }
12662    }
12663
12664    pub fn context_menu_next(
12665        &mut self,
12666        _: &ContextMenuNext,
12667        window: &mut Window,
12668        cx: &mut Context<Self>,
12669    ) {
12670        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12671            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12672        }
12673    }
12674
12675    pub fn context_menu_last(
12676        &mut self,
12677        _: &ContextMenuLast,
12678        window: &mut Window,
12679        cx: &mut Context<Self>,
12680    ) {
12681        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12682            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12683        }
12684    }
12685
12686    pub fn signature_help_prev(
12687        &mut self,
12688        _: &SignatureHelpPrevious,
12689        _: &mut Window,
12690        cx: &mut Context<Self>,
12691    ) {
12692        if let Some(popover) = self.signature_help_state.popover_mut() {
12693            if popover.current_signature == 0 {
12694                popover.current_signature = popover.signatures.len() - 1;
12695            } else {
12696                popover.current_signature -= 1;
12697            }
12698            cx.notify();
12699        }
12700    }
12701
12702    pub fn signature_help_next(
12703        &mut self,
12704        _: &SignatureHelpNext,
12705        _: &mut Window,
12706        cx: &mut Context<Self>,
12707    ) {
12708        if let Some(popover) = self.signature_help_state.popover_mut() {
12709            if popover.current_signature + 1 == popover.signatures.len() {
12710                popover.current_signature = 0;
12711            } else {
12712                popover.current_signature += 1;
12713            }
12714            cx.notify();
12715        }
12716    }
12717
12718    pub fn move_to_previous_word_start(
12719        &mut self,
12720        _: &MoveToPreviousWordStart,
12721        window: &mut Window,
12722        cx: &mut Context<Self>,
12723    ) {
12724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12725        self.change_selections(Default::default(), window, cx, |s| {
12726            s.move_cursors_with(|map, head, _| {
12727                (
12728                    movement::previous_word_start(map, head),
12729                    SelectionGoal::None,
12730                )
12731            });
12732        })
12733    }
12734
12735    pub fn move_to_previous_subword_start(
12736        &mut self,
12737        _: &MoveToPreviousSubwordStart,
12738        window: &mut Window,
12739        cx: &mut Context<Self>,
12740    ) {
12741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12742        self.change_selections(Default::default(), window, cx, |s| {
12743            s.move_cursors_with(|map, head, _| {
12744                (
12745                    movement::previous_subword_start(map, head),
12746                    SelectionGoal::None,
12747                )
12748            });
12749        })
12750    }
12751
12752    pub fn select_to_previous_word_start(
12753        &mut self,
12754        _: &SelectToPreviousWordStart,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_heads_with(|map, head, _| {
12761                (
12762                    movement::previous_word_start(map, head),
12763                    SelectionGoal::None,
12764                )
12765            });
12766        })
12767    }
12768
12769    pub fn select_to_previous_subword_start(
12770        &mut self,
12771        _: &SelectToPreviousSubwordStart,
12772        window: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) {
12775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12776        self.change_selections(Default::default(), window, cx, |s| {
12777            s.move_heads_with(|map, head, _| {
12778                (
12779                    movement::previous_subword_start(map, head),
12780                    SelectionGoal::None,
12781                )
12782            });
12783        })
12784    }
12785
12786    pub fn delete_to_previous_word_start(
12787        &mut self,
12788        action: &DeleteToPreviousWordStart,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12793        self.transact(window, cx, |this, window, cx| {
12794            this.select_autoclose_pair(window, cx);
12795            this.change_selections(Default::default(), window, cx, |s| {
12796                s.move_with(|map, selection| {
12797                    if selection.is_empty() {
12798                        let cursor = if action.ignore_newlines {
12799                            movement::previous_word_start(map, selection.head())
12800                        } else {
12801                            movement::previous_word_start_or_newline(map, selection.head())
12802                        };
12803                        selection.set_head(cursor, SelectionGoal::None);
12804                    }
12805                });
12806            });
12807            this.insert("", window, cx);
12808        });
12809    }
12810
12811    pub fn delete_to_previous_subword_start(
12812        &mut self,
12813        _: &DeleteToPreviousSubwordStart,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12818        self.transact(window, cx, |this, window, cx| {
12819            this.select_autoclose_pair(window, cx);
12820            this.change_selections(Default::default(), window, cx, |s| {
12821                s.move_with(|map, selection| {
12822                    if selection.is_empty() {
12823                        let cursor = movement::previous_subword_start(map, selection.head());
12824                        selection.set_head(cursor, SelectionGoal::None);
12825                    }
12826                });
12827            });
12828            this.insert("", window, cx);
12829        });
12830    }
12831
12832    pub fn move_to_next_word_end(
12833        &mut self,
12834        _: &MoveToNextWordEnd,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12839        self.change_selections(Default::default(), window, cx, |s| {
12840            s.move_cursors_with(|map, head, _| {
12841                (movement::next_word_end(map, head), SelectionGoal::None)
12842            });
12843        })
12844    }
12845
12846    pub fn move_to_next_subword_end(
12847        &mut self,
12848        _: &MoveToNextSubwordEnd,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853        self.change_selections(Default::default(), window, cx, |s| {
12854            s.move_cursors_with(|map, head, _| {
12855                (movement::next_subword_end(map, head), SelectionGoal::None)
12856            });
12857        })
12858    }
12859
12860    pub fn select_to_next_word_end(
12861        &mut self,
12862        _: &SelectToNextWordEnd,
12863        window: &mut Window,
12864        cx: &mut Context<Self>,
12865    ) {
12866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12867        self.change_selections(Default::default(), window, cx, |s| {
12868            s.move_heads_with(|map, head, _| {
12869                (movement::next_word_end(map, head), SelectionGoal::None)
12870            });
12871        })
12872    }
12873
12874    pub fn select_to_next_subword_end(
12875        &mut self,
12876        _: &SelectToNextSubwordEnd,
12877        window: &mut Window,
12878        cx: &mut Context<Self>,
12879    ) {
12880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12881        self.change_selections(Default::default(), window, cx, |s| {
12882            s.move_heads_with(|map, head, _| {
12883                (movement::next_subword_end(map, head), SelectionGoal::None)
12884            });
12885        })
12886    }
12887
12888    pub fn delete_to_next_word_end(
12889        &mut self,
12890        action: &DeleteToNextWordEnd,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12895        self.transact(window, cx, |this, window, cx| {
12896            this.change_selections(Default::default(), window, cx, |s| {
12897                s.move_with(|map, selection| {
12898                    if selection.is_empty() {
12899                        let cursor = if action.ignore_newlines {
12900                            movement::next_word_end(map, selection.head())
12901                        } else {
12902                            movement::next_word_end_or_newline(map, selection.head())
12903                        };
12904                        selection.set_head(cursor, SelectionGoal::None);
12905                    }
12906                });
12907            });
12908            this.insert("", window, cx);
12909        });
12910    }
12911
12912    pub fn delete_to_next_subword_end(
12913        &mut self,
12914        _: &DeleteToNextSubwordEnd,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12919        self.transact(window, cx, |this, window, cx| {
12920            this.change_selections(Default::default(), window, cx, |s| {
12921                s.move_with(|map, selection| {
12922                    if selection.is_empty() {
12923                        let cursor = movement::next_subword_end(map, selection.head());
12924                        selection.set_head(cursor, SelectionGoal::None);
12925                    }
12926                });
12927            });
12928            this.insert("", window, cx);
12929        });
12930    }
12931
12932    pub fn move_to_beginning_of_line(
12933        &mut self,
12934        action: &MoveToBeginningOfLine,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12939        self.change_selections(Default::default(), window, cx, |s| {
12940            s.move_cursors_with(|map, head, _| {
12941                (
12942                    movement::indented_line_beginning(
12943                        map,
12944                        head,
12945                        action.stop_at_soft_wraps,
12946                        action.stop_at_indent,
12947                    ),
12948                    SelectionGoal::None,
12949                )
12950            });
12951        })
12952    }
12953
12954    pub fn select_to_beginning_of_line(
12955        &mut self,
12956        action: &SelectToBeginningOfLine,
12957        window: &mut Window,
12958        cx: &mut Context<Self>,
12959    ) {
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961        self.change_selections(Default::default(), window, cx, |s| {
12962            s.move_heads_with(|map, head, _| {
12963                (
12964                    movement::indented_line_beginning(
12965                        map,
12966                        head,
12967                        action.stop_at_soft_wraps,
12968                        action.stop_at_indent,
12969                    ),
12970                    SelectionGoal::None,
12971                )
12972            });
12973        });
12974    }
12975
12976    pub fn delete_to_beginning_of_line(
12977        &mut self,
12978        action: &DeleteToBeginningOfLine,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12983        self.transact(window, cx, |this, window, cx| {
12984            this.change_selections(Default::default(), window, cx, |s| {
12985                s.move_with(|_, selection| {
12986                    selection.reversed = true;
12987                });
12988            });
12989
12990            this.select_to_beginning_of_line(
12991                &SelectToBeginningOfLine {
12992                    stop_at_soft_wraps: false,
12993                    stop_at_indent: action.stop_at_indent,
12994                },
12995                window,
12996                cx,
12997            );
12998            this.backspace(&Backspace, window, cx);
12999        });
13000    }
13001
13002    pub fn move_to_end_of_line(
13003        &mut self,
13004        action: &MoveToEndOfLine,
13005        window: &mut Window,
13006        cx: &mut Context<Self>,
13007    ) {
13008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13009        self.change_selections(Default::default(), window, cx, |s| {
13010            s.move_cursors_with(|map, head, _| {
13011                (
13012                    movement::line_end(map, head, action.stop_at_soft_wraps),
13013                    SelectionGoal::None,
13014                )
13015            });
13016        })
13017    }
13018
13019    pub fn select_to_end_of_line(
13020        &mut self,
13021        action: &SelectToEndOfLine,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_heads_with(|map, head, _| {
13028                (
13029                    movement::line_end(map, head, action.stop_at_soft_wraps),
13030                    SelectionGoal::None,
13031                )
13032            });
13033        })
13034    }
13035
13036    pub fn delete_to_end_of_line(
13037        &mut self,
13038        _: &DeleteToEndOfLine,
13039        window: &mut Window,
13040        cx: &mut Context<Self>,
13041    ) {
13042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13043        self.transact(window, cx, |this, window, cx| {
13044            this.select_to_end_of_line(
13045                &SelectToEndOfLine {
13046                    stop_at_soft_wraps: false,
13047                },
13048                window,
13049                cx,
13050            );
13051            this.delete(&Delete, window, cx);
13052        });
13053    }
13054
13055    pub fn cut_to_end_of_line(
13056        &mut self,
13057        _: &CutToEndOfLine,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13062        self.transact(window, cx, |this, window, cx| {
13063            this.select_to_end_of_line(
13064                &SelectToEndOfLine {
13065                    stop_at_soft_wraps: false,
13066                },
13067                window,
13068                cx,
13069            );
13070            this.cut(&Cut, window, cx);
13071        });
13072    }
13073
13074    pub fn move_to_start_of_paragraph(
13075        &mut self,
13076        _: &MoveToStartOfParagraph,
13077        window: &mut Window,
13078        cx: &mut Context<Self>,
13079    ) {
13080        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13081            cx.propagate();
13082            return;
13083        }
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        self.change_selections(Default::default(), window, cx, |s| {
13086            s.move_with(|map, selection| {
13087                selection.collapse_to(
13088                    movement::start_of_paragraph(map, selection.head(), 1),
13089                    SelectionGoal::None,
13090                )
13091            });
13092        })
13093    }
13094
13095    pub fn move_to_end_of_paragraph(
13096        &mut self,
13097        _: &MoveToEndOfParagraph,
13098        window: &mut Window,
13099        cx: &mut Context<Self>,
13100    ) {
13101        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13102            cx.propagate();
13103            return;
13104        }
13105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13106        self.change_selections(Default::default(), window, cx, |s| {
13107            s.move_with(|map, selection| {
13108                selection.collapse_to(
13109                    movement::end_of_paragraph(map, selection.head(), 1),
13110                    SelectionGoal::None,
13111                )
13112            });
13113        })
13114    }
13115
13116    pub fn select_to_start_of_paragraph(
13117        &mut self,
13118        _: &SelectToStartOfParagraph,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13123            cx.propagate();
13124            return;
13125        }
13126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13127        self.change_selections(Default::default(), window, cx, |s| {
13128            s.move_heads_with(|map, head, _| {
13129                (
13130                    movement::start_of_paragraph(map, head, 1),
13131                    SelectionGoal::None,
13132                )
13133            });
13134        })
13135    }
13136
13137    pub fn select_to_end_of_paragraph(
13138        &mut self,
13139        _: &SelectToEndOfParagraph,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13144            cx.propagate();
13145            return;
13146        }
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148        self.change_selections(Default::default(), window, cx, |s| {
13149            s.move_heads_with(|map, head, _| {
13150                (
13151                    movement::end_of_paragraph(map, head, 1),
13152                    SelectionGoal::None,
13153                )
13154            });
13155        })
13156    }
13157
13158    pub fn move_to_start_of_excerpt(
13159        &mut self,
13160        _: &MoveToStartOfExcerpt,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13165            cx.propagate();
13166            return;
13167        }
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13169        self.change_selections(Default::default(), window, cx, |s| {
13170            s.move_with(|map, selection| {
13171                selection.collapse_to(
13172                    movement::start_of_excerpt(
13173                        map,
13174                        selection.head(),
13175                        workspace::searchable::Direction::Prev,
13176                    ),
13177                    SelectionGoal::None,
13178                )
13179            });
13180        })
13181    }
13182
13183    pub fn move_to_start_of_next_excerpt(
13184        &mut self,
13185        _: &MoveToStartOfNextExcerpt,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13190            cx.propagate();
13191            return;
13192        }
13193
13194        self.change_selections(Default::default(), window, cx, |s| {
13195            s.move_with(|map, selection| {
13196                selection.collapse_to(
13197                    movement::start_of_excerpt(
13198                        map,
13199                        selection.head(),
13200                        workspace::searchable::Direction::Next,
13201                    ),
13202                    SelectionGoal::None,
13203                )
13204            });
13205        })
13206    }
13207
13208    pub fn move_to_end_of_excerpt(
13209        &mut self,
13210        _: &MoveToEndOfExcerpt,
13211        window: &mut Window,
13212        cx: &mut Context<Self>,
13213    ) {
13214        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13215            cx.propagate();
13216            return;
13217        }
13218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13219        self.change_selections(Default::default(), window, cx, |s| {
13220            s.move_with(|map, selection| {
13221                selection.collapse_to(
13222                    movement::end_of_excerpt(
13223                        map,
13224                        selection.head(),
13225                        workspace::searchable::Direction::Next,
13226                    ),
13227                    SelectionGoal::None,
13228                )
13229            });
13230        })
13231    }
13232
13233    pub fn move_to_end_of_previous_excerpt(
13234        &mut self,
13235        _: &MoveToEndOfPreviousExcerpt,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13240            cx.propagate();
13241            return;
13242        }
13243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13244        self.change_selections(Default::default(), window, cx, |s| {
13245            s.move_with(|map, selection| {
13246                selection.collapse_to(
13247                    movement::end_of_excerpt(
13248                        map,
13249                        selection.head(),
13250                        workspace::searchable::Direction::Prev,
13251                    ),
13252                    SelectionGoal::None,
13253                )
13254            });
13255        })
13256    }
13257
13258    pub fn select_to_start_of_excerpt(
13259        &mut self,
13260        _: &SelectToStartOfExcerpt,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13265            cx.propagate();
13266            return;
13267        }
13268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13269        self.change_selections(Default::default(), window, cx, |s| {
13270            s.move_heads_with(|map, head, _| {
13271                (
13272                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13273                    SelectionGoal::None,
13274                )
13275            });
13276        })
13277    }
13278
13279    pub fn select_to_start_of_next_excerpt(
13280        &mut self,
13281        _: &SelectToStartOfNextExcerpt,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13286            cx.propagate();
13287            return;
13288        }
13289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13290        self.change_selections(Default::default(), window, cx, |s| {
13291            s.move_heads_with(|map, head, _| {
13292                (
13293                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13294                    SelectionGoal::None,
13295                )
13296            });
13297        })
13298    }
13299
13300    pub fn select_to_end_of_excerpt(
13301        &mut self,
13302        _: &SelectToEndOfExcerpt,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13307            cx.propagate();
13308            return;
13309        }
13310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13311        self.change_selections(Default::default(), window, cx, |s| {
13312            s.move_heads_with(|map, head, _| {
13313                (
13314                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13315                    SelectionGoal::None,
13316                )
13317            });
13318        })
13319    }
13320
13321    pub fn select_to_end_of_previous_excerpt(
13322        &mut self,
13323        _: &SelectToEndOfPreviousExcerpt,
13324        window: &mut Window,
13325        cx: &mut Context<Self>,
13326    ) {
13327        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13328            cx.propagate();
13329            return;
13330        }
13331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13332        self.change_selections(Default::default(), window, cx, |s| {
13333            s.move_heads_with(|map, head, _| {
13334                (
13335                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13336                    SelectionGoal::None,
13337                )
13338            });
13339        })
13340    }
13341
13342    pub fn move_to_beginning(
13343        &mut self,
13344        _: &MoveToBeginning,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13349            cx.propagate();
13350            return;
13351        }
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.select_ranges(vec![0..0]);
13355        });
13356    }
13357
13358    pub fn select_to_beginning(
13359        &mut self,
13360        _: &SelectToBeginning,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        let mut selection = self.selections.last::<Point>(cx);
13365        selection.set_head(Point::zero(), SelectionGoal::None);
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.select(vec![selection]);
13369        });
13370    }
13371
13372    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13373        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13374            cx.propagate();
13375            return;
13376        }
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        let cursor = self.buffer.read(cx).read(cx).len();
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.select_ranges(vec![cursor..cursor])
13381        });
13382    }
13383
13384    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13385        self.nav_history = nav_history;
13386    }
13387
13388    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13389        self.nav_history.as_ref()
13390    }
13391
13392    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13393        self.push_to_nav_history(
13394            self.selections.newest_anchor().head(),
13395            None,
13396            false,
13397            true,
13398            cx,
13399        );
13400    }
13401
13402    fn push_to_nav_history(
13403        &mut self,
13404        cursor_anchor: Anchor,
13405        new_position: Option<Point>,
13406        is_deactivate: bool,
13407        always: bool,
13408        cx: &mut Context<Self>,
13409    ) {
13410        if let Some(nav_history) = self.nav_history.as_mut() {
13411            let buffer = self.buffer.read(cx).read(cx);
13412            let cursor_position = cursor_anchor.to_point(&buffer);
13413            let scroll_state = self.scroll_manager.anchor();
13414            let scroll_top_row = scroll_state.top_row(&buffer);
13415            drop(buffer);
13416
13417            if let Some(new_position) = new_position {
13418                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13419                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13420                    return;
13421                }
13422            }
13423
13424            nav_history.push(
13425                Some(NavigationData {
13426                    cursor_anchor,
13427                    cursor_position,
13428                    scroll_anchor: scroll_state,
13429                    scroll_top_row,
13430                }),
13431                cx,
13432            );
13433            cx.emit(EditorEvent::PushedToNavHistory {
13434                anchor: cursor_anchor,
13435                is_deactivate,
13436            })
13437        }
13438    }
13439
13440    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13442        let buffer = self.buffer.read(cx).snapshot(cx);
13443        let mut selection = self.selections.first::<usize>(cx);
13444        selection.set_head(buffer.len(), SelectionGoal::None);
13445        self.change_selections(Default::default(), window, cx, |s| {
13446            s.select(vec![selection]);
13447        });
13448    }
13449
13450    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        let end = self.buffer.read(cx).read(cx).len();
13453        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13454            s.select_ranges(vec![0..end]);
13455        });
13456    }
13457
13458    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13461        let mut selections = self.selections.all::<Point>(cx);
13462        let max_point = display_map.buffer_snapshot.max_point();
13463        for selection in &mut selections {
13464            let rows = selection.spanned_rows(true, &display_map);
13465            selection.start = Point::new(rows.start.0, 0);
13466            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13467            selection.reversed = false;
13468        }
13469        self.change_selections(Default::default(), window, cx, |s| {
13470            s.select(selections);
13471        });
13472    }
13473
13474    pub fn split_selection_into_lines(
13475        &mut self,
13476        _: &SplitSelectionIntoLines,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        let selections = self
13481            .selections
13482            .all::<Point>(cx)
13483            .into_iter()
13484            .map(|selection| selection.start..selection.end)
13485            .collect::<Vec<_>>();
13486        self.unfold_ranges(&selections, true, true, cx);
13487
13488        let mut new_selection_ranges = Vec::new();
13489        {
13490            let buffer = self.buffer.read(cx).read(cx);
13491            for selection in selections {
13492                for row in selection.start.row..selection.end.row {
13493                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13494                    new_selection_ranges.push(cursor..cursor);
13495                }
13496
13497                let is_multiline_selection = selection.start.row != selection.end.row;
13498                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13499                // so this action feels more ergonomic when paired with other selection operations
13500                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13501                if !should_skip_last {
13502                    new_selection_ranges.push(selection.end..selection.end);
13503                }
13504            }
13505        }
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.select_ranges(new_selection_ranges);
13508        });
13509    }
13510
13511    pub fn add_selection_above(
13512        &mut self,
13513        _: &AddSelectionAbove,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        self.add_selection(true, window, cx);
13518    }
13519
13520    pub fn add_selection_below(
13521        &mut self,
13522        _: &AddSelectionBelow,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        self.add_selection(false, window, cx);
13527    }
13528
13529    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13530        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13531
13532        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13533        let all_selections = self.selections.all::<Point>(cx);
13534        let text_layout_details = self.text_layout_details(window);
13535
13536        let (mut columnar_selections, new_selections_to_columnarize) = {
13537            if let Some(state) = self.add_selections_state.as_ref() {
13538                let columnar_selection_ids: HashSet<_> = state
13539                    .groups
13540                    .iter()
13541                    .flat_map(|group| group.stack.iter())
13542                    .copied()
13543                    .collect();
13544
13545                all_selections
13546                    .into_iter()
13547                    .partition(|s| columnar_selection_ids.contains(&s.id))
13548            } else {
13549                (Vec::new(), all_selections)
13550            }
13551        };
13552
13553        let mut state = self
13554            .add_selections_state
13555            .take()
13556            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13557
13558        for selection in new_selections_to_columnarize {
13559            let range = selection.display_range(&display_map).sorted();
13560            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13561            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13562            let positions = start_x.min(end_x)..start_x.max(end_x);
13563            let mut stack = Vec::new();
13564            for row in range.start.row().0..=range.end.row().0 {
13565                if let Some(selection) = self.selections.build_columnar_selection(
13566                    &display_map,
13567                    DisplayRow(row),
13568                    &positions,
13569                    selection.reversed,
13570                    &text_layout_details,
13571                ) {
13572                    stack.push(selection.id);
13573                    columnar_selections.push(selection);
13574                }
13575            }
13576            if !stack.is_empty() {
13577                if above {
13578                    stack.reverse();
13579                }
13580                state.groups.push(AddSelectionsGroup { above, stack });
13581            }
13582        }
13583
13584        let mut final_selections = Vec::new();
13585        let end_row = if above {
13586            DisplayRow(0)
13587        } else {
13588            display_map.max_point().row()
13589        };
13590
13591        let mut last_added_item_per_group = HashMap::default();
13592        for group in state.groups.iter_mut() {
13593            if let Some(last_id) = group.stack.last() {
13594                last_added_item_per_group.insert(*last_id, group);
13595            }
13596        }
13597
13598        for selection in columnar_selections {
13599            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13600                if above == group.above {
13601                    let range = selection.display_range(&display_map).sorted();
13602                    debug_assert_eq!(range.start.row(), range.end.row());
13603                    let mut row = range.start.row();
13604                    let positions =
13605                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13606                            px(start)..px(end)
13607                        } else {
13608                            let start_x =
13609                                display_map.x_for_display_point(range.start, &text_layout_details);
13610                            let end_x =
13611                                display_map.x_for_display_point(range.end, &text_layout_details);
13612                            start_x.min(end_x)..start_x.max(end_x)
13613                        };
13614
13615                    let mut maybe_new_selection = None;
13616                    while row != end_row {
13617                        if above {
13618                            row.0 -= 1;
13619                        } else {
13620                            row.0 += 1;
13621                        }
13622                        if let Some(new_selection) = self.selections.build_columnar_selection(
13623                            &display_map,
13624                            row,
13625                            &positions,
13626                            selection.reversed,
13627                            &text_layout_details,
13628                        ) {
13629                            maybe_new_selection = Some(new_selection);
13630                            break;
13631                        }
13632                    }
13633
13634                    if let Some(new_selection) = maybe_new_selection {
13635                        group.stack.push(new_selection.id);
13636                        if above {
13637                            final_selections.push(new_selection);
13638                            final_selections.push(selection);
13639                        } else {
13640                            final_selections.push(selection);
13641                            final_selections.push(new_selection);
13642                        }
13643                    } else {
13644                        final_selections.push(selection);
13645                    }
13646                } else {
13647                    group.stack.pop();
13648                }
13649            } else {
13650                final_selections.push(selection);
13651            }
13652        }
13653
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.select(final_selections);
13656        });
13657
13658        let final_selection_ids: HashSet<_> = self
13659            .selections
13660            .all::<Point>(cx)
13661            .iter()
13662            .map(|s| s.id)
13663            .collect();
13664        state.groups.retain_mut(|group| {
13665            // selections might get merged above so we remove invalid items from stacks
13666            group.stack.retain(|id| final_selection_ids.contains(id));
13667
13668            // single selection in stack can be treated as initial state
13669            group.stack.len() > 1
13670        });
13671
13672        if !state.groups.is_empty() {
13673            self.add_selections_state = Some(state);
13674        }
13675    }
13676
13677    fn select_match_ranges(
13678        &mut self,
13679        range: Range<usize>,
13680        reversed: bool,
13681        replace_newest: bool,
13682        auto_scroll: Option<Autoscroll>,
13683        window: &mut Window,
13684        cx: &mut Context<Editor>,
13685    ) {
13686        self.unfold_ranges(
13687            std::slice::from_ref(&range),
13688            false,
13689            auto_scroll.is_some(),
13690            cx,
13691        );
13692        let effects = if let Some(scroll) = auto_scroll {
13693            SelectionEffects::scroll(scroll)
13694        } else {
13695            SelectionEffects::no_scroll()
13696        };
13697        self.change_selections(effects, window, cx, |s| {
13698            if replace_newest {
13699                s.delete(s.newest_anchor().id);
13700            }
13701            if reversed {
13702                s.insert_range(range.end..range.start);
13703            } else {
13704                s.insert_range(range);
13705            }
13706        });
13707    }
13708
13709    pub fn select_next_match_internal(
13710        &mut self,
13711        display_map: &DisplaySnapshot,
13712        replace_newest: bool,
13713        autoscroll: Option<Autoscroll>,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) -> Result<()> {
13717        let buffer = &display_map.buffer_snapshot;
13718        let mut selections = self.selections.all::<usize>(cx);
13719        if let Some(mut select_next_state) = self.select_next_state.take() {
13720            let query = &select_next_state.query;
13721            if !select_next_state.done {
13722                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13723                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13724                let mut next_selected_range = None;
13725
13726                let bytes_after_last_selection =
13727                    buffer.bytes_in_range(last_selection.end..buffer.len());
13728                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13729                let query_matches = query
13730                    .stream_find_iter(bytes_after_last_selection)
13731                    .map(|result| (last_selection.end, result))
13732                    .chain(
13733                        query
13734                            .stream_find_iter(bytes_before_first_selection)
13735                            .map(|result| (0, result)),
13736                    );
13737
13738                for (start_offset, query_match) in query_matches {
13739                    let query_match = query_match.unwrap(); // can only fail due to I/O
13740                    let offset_range =
13741                        start_offset + query_match.start()..start_offset + query_match.end();
13742
13743                    if !select_next_state.wordwise
13744                        || (!buffer.is_inside_word(offset_range.start, false)
13745                            && !buffer.is_inside_word(offset_range.end, false))
13746                    {
13747                        // TODO: This is n^2, because we might check all the selections
13748                        if !selections
13749                            .iter()
13750                            .any(|selection| selection.range().overlaps(&offset_range))
13751                        {
13752                            next_selected_range = Some(offset_range);
13753                            break;
13754                        }
13755                    }
13756                }
13757
13758                if let Some(next_selected_range) = next_selected_range {
13759                    self.select_match_ranges(
13760                        next_selected_range,
13761                        last_selection.reversed,
13762                        replace_newest,
13763                        autoscroll,
13764                        window,
13765                        cx,
13766                    );
13767                } else {
13768                    select_next_state.done = true;
13769                }
13770            }
13771
13772            self.select_next_state = Some(select_next_state);
13773        } else {
13774            let mut only_carets = true;
13775            let mut same_text_selected = true;
13776            let mut selected_text = None;
13777
13778            let mut selections_iter = selections.iter().peekable();
13779            while let Some(selection) = selections_iter.next() {
13780                if selection.start != selection.end {
13781                    only_carets = false;
13782                }
13783
13784                if same_text_selected {
13785                    if selected_text.is_none() {
13786                        selected_text =
13787                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13788                    }
13789
13790                    if let Some(next_selection) = selections_iter.peek() {
13791                        if next_selection.range().len() == selection.range().len() {
13792                            let next_selected_text = buffer
13793                                .text_for_range(next_selection.range())
13794                                .collect::<String>();
13795                            if Some(next_selected_text) != selected_text {
13796                                same_text_selected = false;
13797                                selected_text = None;
13798                            }
13799                        } else {
13800                            same_text_selected = false;
13801                            selected_text = None;
13802                        }
13803                    }
13804                }
13805            }
13806
13807            if only_carets {
13808                for selection in &mut selections {
13809                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13810                    selection.start = word_range.start;
13811                    selection.end = word_range.end;
13812                    selection.goal = SelectionGoal::None;
13813                    selection.reversed = false;
13814                    self.select_match_ranges(
13815                        selection.start..selection.end,
13816                        selection.reversed,
13817                        replace_newest,
13818                        autoscroll,
13819                        window,
13820                        cx,
13821                    );
13822                }
13823
13824                if selections.len() == 1 {
13825                    let selection = selections
13826                        .last()
13827                        .expect("ensured that there's only one selection");
13828                    let query = buffer
13829                        .text_for_range(selection.start..selection.end)
13830                        .collect::<String>();
13831                    let is_empty = query.is_empty();
13832                    let select_state = SelectNextState {
13833                        query: AhoCorasick::new(&[query])?,
13834                        wordwise: true,
13835                        done: is_empty,
13836                    };
13837                    self.select_next_state = Some(select_state);
13838                } else {
13839                    self.select_next_state = None;
13840                }
13841            } else if let Some(selected_text) = selected_text {
13842                self.select_next_state = Some(SelectNextState {
13843                    query: AhoCorasick::new(&[selected_text])?,
13844                    wordwise: false,
13845                    done: false,
13846                });
13847                self.select_next_match_internal(
13848                    display_map,
13849                    replace_newest,
13850                    autoscroll,
13851                    window,
13852                    cx,
13853                )?;
13854            }
13855        }
13856        Ok(())
13857    }
13858
13859    pub fn select_all_matches(
13860        &mut self,
13861        _action: &SelectAllMatches,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) -> Result<()> {
13865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13866
13867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13868
13869        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13870        let Some(select_next_state) = self.select_next_state.as_mut() else {
13871            return Ok(());
13872        };
13873        if select_next_state.done {
13874            return Ok(());
13875        }
13876
13877        let mut new_selections = Vec::new();
13878
13879        let reversed = self.selections.oldest::<usize>(cx).reversed;
13880        let buffer = &display_map.buffer_snapshot;
13881        let query_matches = select_next_state
13882            .query
13883            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13884
13885        for query_match in query_matches.into_iter() {
13886            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13887            let offset_range = if reversed {
13888                query_match.end()..query_match.start()
13889            } else {
13890                query_match.start()..query_match.end()
13891            };
13892
13893            if !select_next_state.wordwise
13894                || (!buffer.is_inside_word(offset_range.start, false)
13895                    && !buffer.is_inside_word(offset_range.end, false))
13896            {
13897                new_selections.push(offset_range.start..offset_range.end);
13898            }
13899        }
13900
13901        select_next_state.done = true;
13902
13903        if new_selections.is_empty() {
13904            log::error!("bug: new_selections is empty in select_all_matches");
13905            return Ok(());
13906        }
13907
13908        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13909        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13910            selections.select_ranges(new_selections)
13911        });
13912
13913        Ok(())
13914    }
13915
13916    pub fn select_next(
13917        &mut self,
13918        action: &SelectNext,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) -> Result<()> {
13922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13923        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13924        self.select_next_match_internal(
13925            &display_map,
13926            action.replace_newest,
13927            Some(Autoscroll::newest()),
13928            window,
13929            cx,
13930        )?;
13931        Ok(())
13932    }
13933
13934    pub fn select_previous(
13935        &mut self,
13936        action: &SelectPrevious,
13937        window: &mut Window,
13938        cx: &mut Context<Self>,
13939    ) -> Result<()> {
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13942        let buffer = &display_map.buffer_snapshot;
13943        let mut selections = self.selections.all::<usize>(cx);
13944        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13945            let query = &select_prev_state.query;
13946            if !select_prev_state.done {
13947                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13948                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13949                let mut next_selected_range = None;
13950                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13951                let bytes_before_last_selection =
13952                    buffer.reversed_bytes_in_range(0..last_selection.start);
13953                let bytes_after_first_selection =
13954                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13955                let query_matches = query
13956                    .stream_find_iter(bytes_before_last_selection)
13957                    .map(|result| (last_selection.start, result))
13958                    .chain(
13959                        query
13960                            .stream_find_iter(bytes_after_first_selection)
13961                            .map(|result| (buffer.len(), result)),
13962                    );
13963                for (end_offset, query_match) in query_matches {
13964                    let query_match = query_match.unwrap(); // can only fail due to I/O
13965                    let offset_range =
13966                        end_offset - query_match.end()..end_offset - query_match.start();
13967
13968                    if !select_prev_state.wordwise
13969                        || (!buffer.is_inside_word(offset_range.start, false)
13970                            && !buffer.is_inside_word(offset_range.end, false))
13971                    {
13972                        next_selected_range = Some(offset_range);
13973                        break;
13974                    }
13975                }
13976
13977                if let Some(next_selected_range) = next_selected_range {
13978                    self.select_match_ranges(
13979                        next_selected_range,
13980                        last_selection.reversed,
13981                        action.replace_newest,
13982                        Some(Autoscroll::newest()),
13983                        window,
13984                        cx,
13985                    );
13986                } else {
13987                    select_prev_state.done = true;
13988                }
13989            }
13990
13991            self.select_prev_state = Some(select_prev_state);
13992        } else {
13993            let mut only_carets = true;
13994            let mut same_text_selected = true;
13995            let mut selected_text = None;
13996
13997            let mut selections_iter = selections.iter().peekable();
13998            while let Some(selection) = selections_iter.next() {
13999                if selection.start != selection.end {
14000                    only_carets = false;
14001                }
14002
14003                if same_text_selected {
14004                    if selected_text.is_none() {
14005                        selected_text =
14006                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14007                    }
14008
14009                    if let Some(next_selection) = selections_iter.peek() {
14010                        if next_selection.range().len() == selection.range().len() {
14011                            let next_selected_text = buffer
14012                                .text_for_range(next_selection.range())
14013                                .collect::<String>();
14014                            if Some(next_selected_text) != selected_text {
14015                                same_text_selected = false;
14016                                selected_text = None;
14017                            }
14018                        } else {
14019                            same_text_selected = false;
14020                            selected_text = None;
14021                        }
14022                    }
14023                }
14024            }
14025
14026            if only_carets {
14027                for selection in &mut selections {
14028                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14029                    selection.start = word_range.start;
14030                    selection.end = word_range.end;
14031                    selection.goal = SelectionGoal::None;
14032                    selection.reversed = false;
14033                    self.select_match_ranges(
14034                        selection.start..selection.end,
14035                        selection.reversed,
14036                        action.replace_newest,
14037                        Some(Autoscroll::newest()),
14038                        window,
14039                        cx,
14040                    );
14041                }
14042                if selections.len() == 1 {
14043                    let selection = selections
14044                        .last()
14045                        .expect("ensured that there's only one selection");
14046                    let query = buffer
14047                        .text_for_range(selection.start..selection.end)
14048                        .collect::<String>();
14049                    let is_empty = query.is_empty();
14050                    let select_state = SelectNextState {
14051                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14052                        wordwise: true,
14053                        done: is_empty,
14054                    };
14055                    self.select_prev_state = Some(select_state);
14056                } else {
14057                    self.select_prev_state = None;
14058                }
14059            } else if let Some(selected_text) = selected_text {
14060                self.select_prev_state = Some(SelectNextState {
14061                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14062                    wordwise: false,
14063                    done: false,
14064                });
14065                self.select_previous(action, window, cx)?;
14066            }
14067        }
14068        Ok(())
14069    }
14070
14071    pub fn find_next_match(
14072        &mut self,
14073        _: &FindNextMatch,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) -> Result<()> {
14077        let selections = self.selections.disjoint_anchors();
14078        match selections.first() {
14079            Some(first) if selections.len() >= 2 => {
14080                self.change_selections(Default::default(), window, cx, |s| {
14081                    s.select_ranges([first.range()]);
14082                });
14083            }
14084            _ => self.select_next(
14085                &SelectNext {
14086                    replace_newest: true,
14087                },
14088                window,
14089                cx,
14090            )?,
14091        }
14092        Ok(())
14093    }
14094
14095    pub fn find_previous_match(
14096        &mut self,
14097        _: &FindPreviousMatch,
14098        window: &mut Window,
14099        cx: &mut Context<Self>,
14100    ) -> Result<()> {
14101        let selections = self.selections.disjoint_anchors();
14102        match selections.last() {
14103            Some(last) if selections.len() >= 2 => {
14104                self.change_selections(Default::default(), window, cx, |s| {
14105                    s.select_ranges([last.range()]);
14106                });
14107            }
14108            _ => self.select_previous(
14109                &SelectPrevious {
14110                    replace_newest: true,
14111                },
14112                window,
14113                cx,
14114            )?,
14115        }
14116        Ok(())
14117    }
14118
14119    pub fn toggle_comments(
14120        &mut self,
14121        action: &ToggleComments,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        if self.read_only(cx) {
14126            return;
14127        }
14128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14129        let text_layout_details = &self.text_layout_details(window);
14130        self.transact(window, cx, |this, window, cx| {
14131            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14132            let mut edits = Vec::new();
14133            let mut selection_edit_ranges = Vec::new();
14134            let mut last_toggled_row = None;
14135            let snapshot = this.buffer.read(cx).read(cx);
14136            let empty_str: Arc<str> = Arc::default();
14137            let mut suffixes_inserted = Vec::new();
14138            let ignore_indent = action.ignore_indent;
14139
14140            fn comment_prefix_range(
14141                snapshot: &MultiBufferSnapshot,
14142                row: MultiBufferRow,
14143                comment_prefix: &str,
14144                comment_prefix_whitespace: &str,
14145                ignore_indent: bool,
14146            ) -> Range<Point> {
14147                let indent_size = if ignore_indent {
14148                    0
14149                } else {
14150                    snapshot.indent_size_for_line(row).len
14151                };
14152
14153                let start = Point::new(row.0, indent_size);
14154
14155                let mut line_bytes = snapshot
14156                    .bytes_in_range(start..snapshot.max_point())
14157                    .flatten()
14158                    .copied();
14159
14160                // If this line currently begins with the line comment prefix, then record
14161                // the range containing the prefix.
14162                if line_bytes
14163                    .by_ref()
14164                    .take(comment_prefix.len())
14165                    .eq(comment_prefix.bytes())
14166                {
14167                    // Include any whitespace that matches the comment prefix.
14168                    let matching_whitespace_len = line_bytes
14169                        .zip(comment_prefix_whitespace.bytes())
14170                        .take_while(|(a, b)| a == b)
14171                        .count() as u32;
14172                    let end = Point::new(
14173                        start.row,
14174                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14175                    );
14176                    start..end
14177                } else {
14178                    start..start
14179                }
14180            }
14181
14182            fn comment_suffix_range(
14183                snapshot: &MultiBufferSnapshot,
14184                row: MultiBufferRow,
14185                comment_suffix: &str,
14186                comment_suffix_has_leading_space: bool,
14187            ) -> Range<Point> {
14188                let end = Point::new(row.0, snapshot.line_len(row));
14189                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14190
14191                let mut line_end_bytes = snapshot
14192                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14193                    .flatten()
14194                    .copied();
14195
14196                let leading_space_len = if suffix_start_column > 0
14197                    && line_end_bytes.next() == Some(b' ')
14198                    && comment_suffix_has_leading_space
14199                {
14200                    1
14201                } else {
14202                    0
14203                };
14204
14205                // If this line currently begins with the line comment prefix, then record
14206                // the range containing the prefix.
14207                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14208                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14209                    start..end
14210                } else {
14211                    end..end
14212                }
14213            }
14214
14215            // TODO: Handle selections that cross excerpts
14216            for selection in &mut selections {
14217                let start_column = snapshot
14218                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14219                    .len;
14220                let language = if let Some(language) =
14221                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14222                {
14223                    language
14224                } else {
14225                    continue;
14226                };
14227
14228                selection_edit_ranges.clear();
14229
14230                // If multiple selections contain a given row, avoid processing that
14231                // row more than once.
14232                let mut start_row = MultiBufferRow(selection.start.row);
14233                if last_toggled_row == Some(start_row) {
14234                    start_row = start_row.next_row();
14235                }
14236                let end_row =
14237                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14238                        MultiBufferRow(selection.end.row - 1)
14239                    } else {
14240                        MultiBufferRow(selection.end.row)
14241                    };
14242                last_toggled_row = Some(end_row);
14243
14244                if start_row > end_row {
14245                    continue;
14246                }
14247
14248                // If the language has line comments, toggle those.
14249                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14250
14251                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14252                if ignore_indent {
14253                    full_comment_prefixes = full_comment_prefixes
14254                        .into_iter()
14255                        .map(|s| Arc::from(s.trim_end()))
14256                        .collect();
14257                }
14258
14259                if !full_comment_prefixes.is_empty() {
14260                    let first_prefix = full_comment_prefixes
14261                        .first()
14262                        .expect("prefixes is non-empty");
14263                    let prefix_trimmed_lengths = full_comment_prefixes
14264                        .iter()
14265                        .map(|p| p.trim_end_matches(' ').len())
14266                        .collect::<SmallVec<[usize; 4]>>();
14267
14268                    let mut all_selection_lines_are_comments = true;
14269
14270                    for row in start_row.0..=end_row.0 {
14271                        let row = MultiBufferRow(row);
14272                        if start_row < end_row && snapshot.is_line_blank(row) {
14273                            continue;
14274                        }
14275
14276                        let prefix_range = full_comment_prefixes
14277                            .iter()
14278                            .zip(prefix_trimmed_lengths.iter().copied())
14279                            .map(|(prefix, trimmed_prefix_len)| {
14280                                comment_prefix_range(
14281                                    snapshot.deref(),
14282                                    row,
14283                                    &prefix[..trimmed_prefix_len],
14284                                    &prefix[trimmed_prefix_len..],
14285                                    ignore_indent,
14286                                )
14287                            })
14288                            .max_by_key(|range| range.end.column - range.start.column)
14289                            .expect("prefixes is non-empty");
14290
14291                        if prefix_range.is_empty() {
14292                            all_selection_lines_are_comments = false;
14293                        }
14294
14295                        selection_edit_ranges.push(prefix_range);
14296                    }
14297
14298                    if all_selection_lines_are_comments {
14299                        edits.extend(
14300                            selection_edit_ranges
14301                                .iter()
14302                                .cloned()
14303                                .map(|range| (range, empty_str.clone())),
14304                        );
14305                    } else {
14306                        let min_column = selection_edit_ranges
14307                            .iter()
14308                            .map(|range| range.start.column)
14309                            .min()
14310                            .unwrap_or(0);
14311                        edits.extend(selection_edit_ranges.iter().map(|range| {
14312                            let position = Point::new(range.start.row, min_column);
14313                            (position..position, first_prefix.clone())
14314                        }));
14315                    }
14316                } else if let Some((full_comment_prefix, comment_suffix)) =
14317                    language.block_comment_delimiters()
14318                {
14319                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14320                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14321                    let prefix_range = comment_prefix_range(
14322                        snapshot.deref(),
14323                        start_row,
14324                        comment_prefix,
14325                        comment_prefix_whitespace,
14326                        ignore_indent,
14327                    );
14328                    let suffix_range = comment_suffix_range(
14329                        snapshot.deref(),
14330                        end_row,
14331                        comment_suffix.trim_start_matches(' '),
14332                        comment_suffix.starts_with(' '),
14333                    );
14334
14335                    if prefix_range.is_empty() || suffix_range.is_empty() {
14336                        edits.push((
14337                            prefix_range.start..prefix_range.start,
14338                            full_comment_prefix.clone(),
14339                        ));
14340                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14341                        suffixes_inserted.push((end_row, comment_suffix.len()));
14342                    } else {
14343                        edits.push((prefix_range, empty_str.clone()));
14344                        edits.push((suffix_range, empty_str.clone()));
14345                    }
14346                } else {
14347                    continue;
14348                }
14349            }
14350
14351            drop(snapshot);
14352            this.buffer.update(cx, |buffer, cx| {
14353                buffer.edit(edits, None, cx);
14354            });
14355
14356            // Adjust selections so that they end before any comment suffixes that
14357            // were inserted.
14358            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14359            let mut selections = this.selections.all::<Point>(cx);
14360            let snapshot = this.buffer.read(cx).read(cx);
14361            for selection in &mut selections {
14362                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14363                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14364                        Ordering::Less => {
14365                            suffixes_inserted.next();
14366                            continue;
14367                        }
14368                        Ordering::Greater => break,
14369                        Ordering::Equal => {
14370                            if selection.end.column == snapshot.line_len(row) {
14371                                if selection.is_empty() {
14372                                    selection.start.column -= suffix_len as u32;
14373                                }
14374                                selection.end.column -= suffix_len as u32;
14375                            }
14376                            break;
14377                        }
14378                    }
14379                }
14380            }
14381
14382            drop(snapshot);
14383            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14384
14385            let selections = this.selections.all::<Point>(cx);
14386            let selections_on_single_row = selections.windows(2).all(|selections| {
14387                selections[0].start.row == selections[1].start.row
14388                    && selections[0].end.row == selections[1].end.row
14389                    && selections[0].start.row == selections[0].end.row
14390            });
14391            let selections_selecting = selections
14392                .iter()
14393                .any(|selection| selection.start != selection.end);
14394            let advance_downwards = action.advance_downwards
14395                && selections_on_single_row
14396                && !selections_selecting
14397                && !matches!(this.mode, EditorMode::SingleLine { .. });
14398
14399            if advance_downwards {
14400                let snapshot = this.buffer.read(cx).snapshot(cx);
14401
14402                this.change_selections(Default::default(), window, cx, |s| {
14403                    s.move_cursors_with(|display_snapshot, display_point, _| {
14404                        let mut point = display_point.to_point(display_snapshot);
14405                        point.row += 1;
14406                        point = snapshot.clip_point(point, Bias::Left);
14407                        let display_point = point.to_display_point(display_snapshot);
14408                        let goal = SelectionGoal::HorizontalPosition(
14409                            display_snapshot
14410                                .x_for_display_point(display_point, text_layout_details)
14411                                .into(),
14412                        );
14413                        (display_point, goal)
14414                    })
14415                });
14416            }
14417        });
14418    }
14419
14420    pub fn select_enclosing_symbol(
14421        &mut self,
14422        _: &SelectEnclosingSymbol,
14423        window: &mut Window,
14424        cx: &mut Context<Self>,
14425    ) {
14426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14427
14428        let buffer = self.buffer.read(cx).snapshot(cx);
14429        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14430
14431        fn update_selection(
14432            selection: &Selection<usize>,
14433            buffer_snap: &MultiBufferSnapshot,
14434        ) -> Option<Selection<usize>> {
14435            let cursor = selection.head();
14436            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14437            for symbol in symbols.iter().rev() {
14438                let start = symbol.range.start.to_offset(buffer_snap);
14439                let end = symbol.range.end.to_offset(buffer_snap);
14440                let new_range = start..end;
14441                if start < selection.start || end > selection.end {
14442                    return Some(Selection {
14443                        id: selection.id,
14444                        start: new_range.start,
14445                        end: new_range.end,
14446                        goal: SelectionGoal::None,
14447                        reversed: selection.reversed,
14448                    });
14449                }
14450            }
14451            None
14452        }
14453
14454        let mut selected_larger_symbol = false;
14455        let new_selections = old_selections
14456            .iter()
14457            .map(|selection| match update_selection(selection, &buffer) {
14458                Some(new_selection) => {
14459                    if new_selection.range() != selection.range() {
14460                        selected_larger_symbol = true;
14461                    }
14462                    new_selection
14463                }
14464                None => selection.clone(),
14465            })
14466            .collect::<Vec<_>>();
14467
14468        if selected_larger_symbol {
14469            self.change_selections(Default::default(), window, cx, |s| {
14470                s.select(new_selections);
14471            });
14472        }
14473    }
14474
14475    pub fn select_larger_syntax_node(
14476        &mut self,
14477        _: &SelectLargerSyntaxNode,
14478        window: &mut Window,
14479        cx: &mut Context<Self>,
14480    ) {
14481        let Some(visible_row_count) = self.visible_row_count() else {
14482            return;
14483        };
14484        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14485        if old_selections.is_empty() {
14486            return;
14487        }
14488
14489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14490
14491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14492        let buffer = self.buffer.read(cx).snapshot(cx);
14493
14494        let mut selected_larger_node = false;
14495        let mut new_selections = old_selections
14496            .iter()
14497            .map(|selection| {
14498                let old_range = selection.start..selection.end;
14499
14500                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14501                    // manually select word at selection
14502                    if ["string_content", "inline"].contains(&node.kind()) {
14503                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14504                        // ignore if word is already selected
14505                        if !word_range.is_empty() && old_range != word_range {
14506                            let (last_word_range, _) =
14507                                buffer.surrounding_word(old_range.end, false);
14508                            // only select word if start and end point belongs to same word
14509                            if word_range == last_word_range {
14510                                selected_larger_node = true;
14511                                return Selection {
14512                                    id: selection.id,
14513                                    start: word_range.start,
14514                                    end: word_range.end,
14515                                    goal: SelectionGoal::None,
14516                                    reversed: selection.reversed,
14517                                };
14518                            }
14519                        }
14520                    }
14521                }
14522
14523                let mut new_range = old_range.clone();
14524                while let Some((_node, containing_range)) =
14525                    buffer.syntax_ancestor(new_range.clone())
14526                {
14527                    new_range = match containing_range {
14528                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14529                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14530                    };
14531                    if !display_map.intersects_fold(new_range.start)
14532                        && !display_map.intersects_fold(new_range.end)
14533                    {
14534                        break;
14535                    }
14536                }
14537
14538                selected_larger_node |= new_range != old_range;
14539                Selection {
14540                    id: selection.id,
14541                    start: new_range.start,
14542                    end: new_range.end,
14543                    goal: SelectionGoal::None,
14544                    reversed: selection.reversed,
14545                }
14546            })
14547            .collect::<Vec<_>>();
14548
14549        if !selected_larger_node {
14550            return; // don't put this call in the history
14551        }
14552
14553        // scroll based on transformation done to the last selection created by the user
14554        let (last_old, last_new) = old_selections
14555            .last()
14556            .zip(new_selections.last().cloned())
14557            .expect("old_selections isn't empty");
14558
14559        // revert selection
14560        let is_selection_reversed = {
14561            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14562            new_selections.last_mut().expect("checked above").reversed =
14563                should_newest_selection_be_reversed;
14564            should_newest_selection_be_reversed
14565        };
14566
14567        if selected_larger_node {
14568            self.select_syntax_node_history.disable_clearing = true;
14569            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14570                s.select(new_selections.clone());
14571            });
14572            self.select_syntax_node_history.disable_clearing = false;
14573        }
14574
14575        let start_row = last_new.start.to_display_point(&display_map).row().0;
14576        let end_row = last_new.end.to_display_point(&display_map).row().0;
14577        let selection_height = end_row - start_row + 1;
14578        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14579
14580        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14581        let scroll_behavior = if fits_on_the_screen {
14582            self.request_autoscroll(Autoscroll::fit(), cx);
14583            SelectSyntaxNodeScrollBehavior::FitSelection
14584        } else if is_selection_reversed {
14585            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14586            SelectSyntaxNodeScrollBehavior::CursorTop
14587        } else {
14588            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14589            SelectSyntaxNodeScrollBehavior::CursorBottom
14590        };
14591
14592        self.select_syntax_node_history.push((
14593            old_selections,
14594            scroll_behavior,
14595            is_selection_reversed,
14596        ));
14597    }
14598
14599    pub fn select_smaller_syntax_node(
14600        &mut self,
14601        _: &SelectSmallerSyntaxNode,
14602        window: &mut Window,
14603        cx: &mut Context<Self>,
14604    ) {
14605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14606
14607        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14608            self.select_syntax_node_history.pop()
14609        {
14610            if let Some(selection) = selections.last_mut() {
14611                selection.reversed = is_selection_reversed;
14612            }
14613
14614            self.select_syntax_node_history.disable_clearing = true;
14615            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14616                s.select(selections.to_vec());
14617            });
14618            self.select_syntax_node_history.disable_clearing = false;
14619
14620            match scroll_behavior {
14621                SelectSyntaxNodeScrollBehavior::CursorTop => {
14622                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14623                }
14624                SelectSyntaxNodeScrollBehavior::FitSelection => {
14625                    self.request_autoscroll(Autoscroll::fit(), cx);
14626                }
14627                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14628                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14629                }
14630            }
14631        }
14632    }
14633
14634    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14635        if !EditorSettings::get_global(cx).gutter.runnables {
14636            self.clear_tasks();
14637            return Task::ready(());
14638        }
14639        let project = self.project.as_ref().map(Entity::downgrade);
14640        let task_sources = self.lsp_task_sources(cx);
14641        let multi_buffer = self.buffer.downgrade();
14642        cx.spawn_in(window, async move |editor, cx| {
14643            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14644            let Some(project) = project.and_then(|p| p.upgrade()) else {
14645                return;
14646            };
14647            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14648                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14649            }) else {
14650                return;
14651            };
14652
14653            let hide_runnables = project
14654                .update(cx, |project, cx| {
14655                    // Do not display any test indicators in non-dev server remote projects.
14656                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14657                })
14658                .unwrap_or(true);
14659            if hide_runnables {
14660                return;
14661            }
14662            let new_rows =
14663                cx.background_spawn({
14664                    let snapshot = display_snapshot.clone();
14665                    async move {
14666                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14667                    }
14668                })
14669                    .await;
14670            let Ok(lsp_tasks) =
14671                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14672            else {
14673                return;
14674            };
14675            let lsp_tasks = lsp_tasks.await;
14676
14677            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14678                lsp_tasks
14679                    .into_iter()
14680                    .flat_map(|(kind, tasks)| {
14681                        tasks.into_iter().filter_map(move |(location, task)| {
14682                            Some((kind.clone(), location?, task))
14683                        })
14684                    })
14685                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14686                        let buffer = location.target.buffer;
14687                        let buffer_snapshot = buffer.read(cx).snapshot();
14688                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14689                            |(excerpt_id, snapshot, _)| {
14690                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14691                                    display_snapshot
14692                                        .buffer_snapshot
14693                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14694                                } else {
14695                                    None
14696                                }
14697                            },
14698                        );
14699                        if let Some(offset) = offset {
14700                            let task_buffer_range =
14701                                location.target.range.to_point(&buffer_snapshot);
14702                            let context_buffer_range =
14703                                task_buffer_range.to_offset(&buffer_snapshot);
14704                            let context_range = BufferOffset(context_buffer_range.start)
14705                                ..BufferOffset(context_buffer_range.end);
14706
14707                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14708                                .or_insert_with(|| RunnableTasks {
14709                                    templates: Vec::new(),
14710                                    offset,
14711                                    column: task_buffer_range.start.column,
14712                                    extra_variables: HashMap::default(),
14713                                    context_range,
14714                                })
14715                                .templates
14716                                .push((kind, task.original_task().clone()));
14717                        }
14718
14719                        acc
14720                    })
14721            }) else {
14722                return;
14723            };
14724
14725            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14726                buffer.language_settings(cx).tasks.prefer_lsp
14727            }) else {
14728                return;
14729            };
14730
14731            let rows = Self::runnable_rows(
14732                project,
14733                display_snapshot,
14734                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14735                new_rows,
14736                cx.clone(),
14737            )
14738            .await;
14739            editor
14740                .update(cx, |editor, _| {
14741                    editor.clear_tasks();
14742                    for (key, mut value) in rows {
14743                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14744                            value.templates.extend(lsp_tasks.templates);
14745                        }
14746
14747                        editor.insert_tasks(key, value);
14748                    }
14749                    for (key, value) in lsp_tasks_by_rows {
14750                        editor.insert_tasks(key, value);
14751                    }
14752                })
14753                .ok();
14754        })
14755    }
14756    fn fetch_runnable_ranges(
14757        snapshot: &DisplaySnapshot,
14758        range: Range<Anchor>,
14759    ) -> Vec<language::RunnableRange> {
14760        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14761    }
14762
14763    fn runnable_rows(
14764        project: Entity<Project>,
14765        snapshot: DisplaySnapshot,
14766        prefer_lsp: bool,
14767        runnable_ranges: Vec<RunnableRange>,
14768        cx: AsyncWindowContext,
14769    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14770        cx.spawn(async move |cx| {
14771            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14772            for mut runnable in runnable_ranges {
14773                let Some(tasks) = cx
14774                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14775                    .ok()
14776                else {
14777                    continue;
14778                };
14779                let mut tasks = tasks.await;
14780
14781                if prefer_lsp {
14782                    tasks.retain(|(task_kind, _)| {
14783                        !matches!(task_kind, TaskSourceKind::Language { .. })
14784                    });
14785                }
14786                if tasks.is_empty() {
14787                    continue;
14788                }
14789
14790                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14791                let Some(row) = snapshot
14792                    .buffer_snapshot
14793                    .buffer_line_for_row(MultiBufferRow(point.row))
14794                    .map(|(_, range)| range.start.row)
14795                else {
14796                    continue;
14797                };
14798
14799                let context_range =
14800                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14801                runnable_rows.push((
14802                    (runnable.buffer_id, row),
14803                    RunnableTasks {
14804                        templates: tasks,
14805                        offset: snapshot
14806                            .buffer_snapshot
14807                            .anchor_before(runnable.run_range.start),
14808                        context_range,
14809                        column: point.column,
14810                        extra_variables: runnable.extra_captures,
14811                    },
14812                ));
14813            }
14814            runnable_rows
14815        })
14816    }
14817
14818    fn templates_with_tags(
14819        project: &Entity<Project>,
14820        runnable: &mut Runnable,
14821        cx: &mut App,
14822    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14823        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14824            let (worktree_id, file) = project
14825                .buffer_for_id(runnable.buffer, cx)
14826                .and_then(|buffer| buffer.read(cx).file())
14827                .map(|file| (file.worktree_id(cx), file.clone()))
14828                .unzip();
14829
14830            (
14831                project.task_store().read(cx).task_inventory().cloned(),
14832                worktree_id,
14833                file,
14834            )
14835        });
14836
14837        let tags = mem::take(&mut runnable.tags);
14838        let language = runnable.language.clone();
14839        cx.spawn(async move |cx| {
14840            let mut templates_with_tags = Vec::new();
14841            if let Some(inventory) = inventory {
14842                for RunnableTag(tag) in tags {
14843                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14844                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14845                    }) else {
14846                        return templates_with_tags;
14847                    };
14848                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14849                        move |(_, template)| {
14850                            template.tags.iter().any(|source_tag| source_tag == &tag)
14851                        },
14852                    ));
14853                }
14854            }
14855            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14856
14857            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14858                // Strongest source wins; if we have worktree tag binding, prefer that to
14859                // global and language bindings;
14860                // if we have a global binding, prefer that to language binding.
14861                let first_mismatch = templates_with_tags
14862                    .iter()
14863                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14864                if let Some(index) = first_mismatch {
14865                    templates_with_tags.truncate(index);
14866                }
14867            }
14868
14869            templates_with_tags
14870        })
14871    }
14872
14873    pub fn move_to_enclosing_bracket(
14874        &mut self,
14875        _: &MoveToEnclosingBracket,
14876        window: &mut Window,
14877        cx: &mut Context<Self>,
14878    ) {
14879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14880        self.change_selections(Default::default(), window, cx, |s| {
14881            s.move_offsets_with(|snapshot, selection| {
14882                let Some(enclosing_bracket_ranges) =
14883                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14884                else {
14885                    return;
14886                };
14887
14888                let mut best_length = usize::MAX;
14889                let mut best_inside = false;
14890                let mut best_in_bracket_range = false;
14891                let mut best_destination = None;
14892                for (open, close) in enclosing_bracket_ranges {
14893                    let close = close.to_inclusive();
14894                    let length = close.end() - open.start;
14895                    let inside = selection.start >= open.end && selection.end <= *close.start();
14896                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14897                        || close.contains(&selection.head());
14898
14899                    // If best is next to a bracket and current isn't, skip
14900                    if !in_bracket_range && best_in_bracket_range {
14901                        continue;
14902                    }
14903
14904                    // Prefer smaller lengths unless best is inside and current isn't
14905                    if length > best_length && (best_inside || !inside) {
14906                        continue;
14907                    }
14908
14909                    best_length = length;
14910                    best_inside = inside;
14911                    best_in_bracket_range = in_bracket_range;
14912                    best_destination = Some(
14913                        if close.contains(&selection.start) && close.contains(&selection.end) {
14914                            if inside { open.end } else { open.start }
14915                        } else if inside {
14916                            *close.start()
14917                        } else {
14918                            *close.end()
14919                        },
14920                    );
14921                }
14922
14923                if let Some(destination) = best_destination {
14924                    selection.collapse_to(destination, SelectionGoal::None);
14925                }
14926            })
14927        });
14928    }
14929
14930    pub fn undo_selection(
14931        &mut self,
14932        _: &UndoSelection,
14933        window: &mut Window,
14934        cx: &mut Context<Self>,
14935    ) {
14936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14937        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14938            self.selection_history.mode = SelectionHistoryMode::Undoing;
14939            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14940                this.end_selection(window, cx);
14941                this.change_selections(
14942                    SelectionEffects::scroll(Autoscroll::newest()),
14943                    window,
14944                    cx,
14945                    |s| s.select_anchors(entry.selections.to_vec()),
14946                );
14947            });
14948            self.selection_history.mode = SelectionHistoryMode::Normal;
14949
14950            self.select_next_state = entry.select_next_state;
14951            self.select_prev_state = entry.select_prev_state;
14952            self.add_selections_state = entry.add_selections_state;
14953        }
14954    }
14955
14956    pub fn redo_selection(
14957        &mut self,
14958        _: &RedoSelection,
14959        window: &mut Window,
14960        cx: &mut Context<Self>,
14961    ) {
14962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14963        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14964            self.selection_history.mode = SelectionHistoryMode::Redoing;
14965            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14966                this.end_selection(window, cx);
14967                this.change_selections(
14968                    SelectionEffects::scroll(Autoscroll::newest()),
14969                    window,
14970                    cx,
14971                    |s| s.select_anchors(entry.selections.to_vec()),
14972                );
14973            });
14974            self.selection_history.mode = SelectionHistoryMode::Normal;
14975
14976            self.select_next_state = entry.select_next_state;
14977            self.select_prev_state = entry.select_prev_state;
14978            self.add_selections_state = entry.add_selections_state;
14979        }
14980    }
14981
14982    pub fn expand_excerpts(
14983        &mut self,
14984        action: &ExpandExcerpts,
14985        _: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) {
14988        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14989    }
14990
14991    pub fn expand_excerpts_down(
14992        &mut self,
14993        action: &ExpandExcerptsDown,
14994        _: &mut Window,
14995        cx: &mut Context<Self>,
14996    ) {
14997        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14998    }
14999
15000    pub fn expand_excerpts_up(
15001        &mut self,
15002        action: &ExpandExcerptsUp,
15003        _: &mut Window,
15004        cx: &mut Context<Self>,
15005    ) {
15006        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15007    }
15008
15009    pub fn expand_excerpts_for_direction(
15010        &mut self,
15011        lines: u32,
15012        direction: ExpandExcerptDirection,
15013
15014        cx: &mut Context<Self>,
15015    ) {
15016        let selections = self.selections.disjoint_anchors();
15017
15018        let lines = if lines == 0 {
15019            EditorSettings::get_global(cx).expand_excerpt_lines
15020        } else {
15021            lines
15022        };
15023
15024        self.buffer.update(cx, |buffer, cx| {
15025            let snapshot = buffer.snapshot(cx);
15026            let mut excerpt_ids = selections
15027                .iter()
15028                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15029                .collect::<Vec<_>>();
15030            excerpt_ids.sort();
15031            excerpt_ids.dedup();
15032            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15033        })
15034    }
15035
15036    pub fn expand_excerpt(
15037        &mut self,
15038        excerpt: ExcerptId,
15039        direction: ExpandExcerptDirection,
15040        window: &mut Window,
15041        cx: &mut Context<Self>,
15042    ) {
15043        let current_scroll_position = self.scroll_position(cx);
15044        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15045        let mut should_scroll_up = false;
15046
15047        if direction == ExpandExcerptDirection::Down {
15048            let multi_buffer = self.buffer.read(cx);
15049            let snapshot = multi_buffer.snapshot(cx);
15050            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15051                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15052                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15053                        let buffer_snapshot = buffer.read(cx).snapshot();
15054                        let excerpt_end_row =
15055                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15056                        let last_row = buffer_snapshot.max_point().row;
15057                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15058                        should_scroll_up = lines_below >= lines_to_expand;
15059                    }
15060                }
15061            }
15062        }
15063
15064        self.buffer.update(cx, |buffer, cx| {
15065            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15066        });
15067
15068        if should_scroll_up {
15069            let new_scroll_position =
15070                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15071            self.set_scroll_position(new_scroll_position, window, cx);
15072        }
15073    }
15074
15075    pub fn go_to_singleton_buffer_point(
15076        &mut self,
15077        point: Point,
15078        window: &mut Window,
15079        cx: &mut Context<Self>,
15080    ) {
15081        self.go_to_singleton_buffer_range(point..point, window, cx);
15082    }
15083
15084    pub fn go_to_singleton_buffer_range(
15085        &mut self,
15086        range: Range<Point>,
15087        window: &mut Window,
15088        cx: &mut Context<Self>,
15089    ) {
15090        let multibuffer = self.buffer().read(cx);
15091        let Some(buffer) = multibuffer.as_singleton() else {
15092            return;
15093        };
15094        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15095            return;
15096        };
15097        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15098            return;
15099        };
15100        self.change_selections(
15101            SelectionEffects::default().nav_history(true),
15102            window,
15103            cx,
15104            |s| s.select_anchor_ranges([start..end]),
15105        );
15106    }
15107
15108    pub fn go_to_diagnostic(
15109        &mut self,
15110        action: &GoToDiagnostic,
15111        window: &mut Window,
15112        cx: &mut Context<Self>,
15113    ) {
15114        if !self.diagnostics_enabled() {
15115            return;
15116        }
15117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15118        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15119    }
15120
15121    pub fn go_to_prev_diagnostic(
15122        &mut self,
15123        action: &GoToPreviousDiagnostic,
15124        window: &mut Window,
15125        cx: &mut Context<Self>,
15126    ) {
15127        if !self.diagnostics_enabled() {
15128            return;
15129        }
15130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15131        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15132    }
15133
15134    pub fn go_to_diagnostic_impl(
15135        &mut self,
15136        direction: Direction,
15137        severity: GoToDiagnosticSeverityFilter,
15138        window: &mut Window,
15139        cx: &mut Context<Self>,
15140    ) {
15141        let buffer = self.buffer.read(cx).snapshot(cx);
15142        let selection = self.selections.newest::<usize>(cx);
15143
15144        let mut active_group_id = None;
15145        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15146            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15147                active_group_id = Some(active_group.group_id);
15148            }
15149        }
15150
15151        fn filtered(
15152            snapshot: EditorSnapshot,
15153            severity: GoToDiagnosticSeverityFilter,
15154            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15155        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15156            diagnostics
15157                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15158                .filter(|entry| entry.range.start != entry.range.end)
15159                .filter(|entry| !entry.diagnostic.is_unnecessary)
15160                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15161        }
15162
15163        let snapshot = self.snapshot(window, cx);
15164        let before = filtered(
15165            snapshot.clone(),
15166            severity,
15167            buffer
15168                .diagnostics_in_range(0..selection.start)
15169                .filter(|entry| entry.range.start <= selection.start),
15170        );
15171        let after = filtered(
15172            snapshot,
15173            severity,
15174            buffer
15175                .diagnostics_in_range(selection.start..buffer.len())
15176                .filter(|entry| entry.range.start >= selection.start),
15177        );
15178
15179        let mut found: Option<DiagnosticEntry<usize>> = None;
15180        if direction == Direction::Prev {
15181            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15182            {
15183                for diagnostic in prev_diagnostics.into_iter().rev() {
15184                    if diagnostic.range.start != selection.start
15185                        || active_group_id
15186                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15187                    {
15188                        found = Some(diagnostic);
15189                        break 'outer;
15190                    }
15191                }
15192            }
15193        } else {
15194            for diagnostic in after.chain(before) {
15195                if diagnostic.range.start != selection.start
15196                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15197                {
15198                    found = Some(diagnostic);
15199                    break;
15200                }
15201            }
15202        }
15203        let Some(next_diagnostic) = found else {
15204            return;
15205        };
15206
15207        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15208            return;
15209        };
15210        self.change_selections(Default::default(), window, cx, |s| {
15211            s.select_ranges(vec![
15212                next_diagnostic.range.start..next_diagnostic.range.start,
15213            ])
15214        });
15215        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15216        self.refresh_inline_completion(false, true, window, cx);
15217    }
15218
15219    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15221        let snapshot = self.snapshot(window, cx);
15222        let selection = self.selections.newest::<Point>(cx);
15223        self.go_to_hunk_before_or_after_position(
15224            &snapshot,
15225            selection.head(),
15226            Direction::Next,
15227            window,
15228            cx,
15229        );
15230    }
15231
15232    pub fn go_to_hunk_before_or_after_position(
15233        &mut self,
15234        snapshot: &EditorSnapshot,
15235        position: Point,
15236        direction: Direction,
15237        window: &mut Window,
15238        cx: &mut Context<Editor>,
15239    ) {
15240        let row = if direction == Direction::Next {
15241            self.hunk_after_position(snapshot, position)
15242                .map(|hunk| hunk.row_range.start)
15243        } else {
15244            self.hunk_before_position(snapshot, position)
15245        };
15246
15247        if let Some(row) = row {
15248            let destination = Point::new(row.0, 0);
15249            let autoscroll = Autoscroll::center();
15250
15251            self.unfold_ranges(&[destination..destination], false, false, cx);
15252            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15253                s.select_ranges([destination..destination]);
15254            });
15255        }
15256    }
15257
15258    fn hunk_after_position(
15259        &mut self,
15260        snapshot: &EditorSnapshot,
15261        position: Point,
15262    ) -> Option<MultiBufferDiffHunk> {
15263        snapshot
15264            .buffer_snapshot
15265            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15266            .find(|hunk| hunk.row_range.start.0 > position.row)
15267            .or_else(|| {
15268                snapshot
15269                    .buffer_snapshot
15270                    .diff_hunks_in_range(Point::zero()..position)
15271                    .find(|hunk| hunk.row_range.end.0 < position.row)
15272            })
15273    }
15274
15275    fn go_to_prev_hunk(
15276        &mut self,
15277        _: &GoToPreviousHunk,
15278        window: &mut Window,
15279        cx: &mut Context<Self>,
15280    ) {
15281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15282        let snapshot = self.snapshot(window, cx);
15283        let selection = self.selections.newest::<Point>(cx);
15284        self.go_to_hunk_before_or_after_position(
15285            &snapshot,
15286            selection.head(),
15287            Direction::Prev,
15288            window,
15289            cx,
15290        );
15291    }
15292
15293    fn hunk_before_position(
15294        &mut self,
15295        snapshot: &EditorSnapshot,
15296        position: Point,
15297    ) -> Option<MultiBufferRow> {
15298        snapshot
15299            .buffer_snapshot
15300            .diff_hunk_before(position)
15301            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15302    }
15303
15304    fn go_to_next_change(
15305        &mut self,
15306        _: &GoToNextChange,
15307        window: &mut Window,
15308        cx: &mut Context<Self>,
15309    ) {
15310        if let Some(selections) = self
15311            .change_list
15312            .next_change(1, Direction::Next)
15313            .map(|s| s.to_vec())
15314        {
15315            self.change_selections(Default::default(), window, cx, |s| {
15316                let map = s.display_map();
15317                s.select_display_ranges(selections.iter().map(|a| {
15318                    let point = a.to_display_point(&map);
15319                    point..point
15320                }))
15321            })
15322        }
15323    }
15324
15325    fn go_to_previous_change(
15326        &mut self,
15327        _: &GoToPreviousChange,
15328        window: &mut Window,
15329        cx: &mut Context<Self>,
15330    ) {
15331        if let Some(selections) = self
15332            .change_list
15333            .next_change(1, Direction::Prev)
15334            .map(|s| s.to_vec())
15335        {
15336            self.change_selections(Default::default(), window, cx, |s| {
15337                let map = s.display_map();
15338                s.select_display_ranges(selections.iter().map(|a| {
15339                    let point = a.to_display_point(&map);
15340                    point..point
15341                }))
15342            })
15343        }
15344    }
15345
15346    fn go_to_line<T: 'static>(
15347        &mut self,
15348        position: Anchor,
15349        highlight_color: Option<Hsla>,
15350        window: &mut Window,
15351        cx: &mut Context<Self>,
15352    ) {
15353        let snapshot = self.snapshot(window, cx).display_snapshot;
15354        let position = position.to_point(&snapshot.buffer_snapshot);
15355        let start = snapshot
15356            .buffer_snapshot
15357            .clip_point(Point::new(position.row, 0), Bias::Left);
15358        let end = start + Point::new(1, 0);
15359        let start = snapshot.buffer_snapshot.anchor_before(start);
15360        let end = snapshot.buffer_snapshot.anchor_before(end);
15361
15362        self.highlight_rows::<T>(
15363            start..end,
15364            highlight_color
15365                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15366            Default::default(),
15367            cx,
15368        );
15369
15370        if self.buffer.read(cx).is_singleton() {
15371            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15372        }
15373    }
15374
15375    pub fn go_to_definition(
15376        &mut self,
15377        _: &GoToDefinition,
15378        window: &mut Window,
15379        cx: &mut Context<Self>,
15380    ) -> Task<Result<Navigated>> {
15381        let definition =
15382            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15383        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15384        cx.spawn_in(window, async move |editor, cx| {
15385            if definition.await? == Navigated::Yes {
15386                return Ok(Navigated::Yes);
15387            }
15388            match fallback_strategy {
15389                GoToDefinitionFallback::None => Ok(Navigated::No),
15390                GoToDefinitionFallback::FindAllReferences => {
15391                    match editor.update_in(cx, |editor, window, cx| {
15392                        editor.find_all_references(&FindAllReferences, window, cx)
15393                    })? {
15394                        Some(references) => references.await,
15395                        None => Ok(Navigated::No),
15396                    }
15397                }
15398            }
15399        })
15400    }
15401
15402    pub fn go_to_declaration(
15403        &mut self,
15404        _: &GoToDeclaration,
15405        window: &mut Window,
15406        cx: &mut Context<Self>,
15407    ) -> Task<Result<Navigated>> {
15408        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15409    }
15410
15411    pub fn go_to_declaration_split(
15412        &mut self,
15413        _: &GoToDeclaration,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) -> Task<Result<Navigated>> {
15417        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15418    }
15419
15420    pub fn go_to_implementation(
15421        &mut self,
15422        _: &GoToImplementation,
15423        window: &mut Window,
15424        cx: &mut Context<Self>,
15425    ) -> Task<Result<Navigated>> {
15426        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15427    }
15428
15429    pub fn go_to_implementation_split(
15430        &mut self,
15431        _: &GoToImplementationSplit,
15432        window: &mut Window,
15433        cx: &mut Context<Self>,
15434    ) -> Task<Result<Navigated>> {
15435        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15436    }
15437
15438    pub fn go_to_type_definition(
15439        &mut self,
15440        _: &GoToTypeDefinition,
15441        window: &mut Window,
15442        cx: &mut Context<Self>,
15443    ) -> Task<Result<Navigated>> {
15444        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15445    }
15446
15447    pub fn go_to_definition_split(
15448        &mut self,
15449        _: &GoToDefinitionSplit,
15450        window: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) -> Task<Result<Navigated>> {
15453        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15454    }
15455
15456    pub fn go_to_type_definition_split(
15457        &mut self,
15458        _: &GoToTypeDefinitionSplit,
15459        window: &mut Window,
15460        cx: &mut Context<Self>,
15461    ) -> Task<Result<Navigated>> {
15462        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15463    }
15464
15465    fn go_to_definition_of_kind(
15466        &mut self,
15467        kind: GotoDefinitionKind,
15468        split: bool,
15469        window: &mut Window,
15470        cx: &mut Context<Self>,
15471    ) -> Task<Result<Navigated>> {
15472        let Some(provider) = self.semantics_provider.clone() else {
15473            return Task::ready(Ok(Navigated::No));
15474        };
15475        let head = self.selections.newest::<usize>(cx).head();
15476        let buffer = self.buffer.read(cx);
15477        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15478            text_anchor
15479        } else {
15480            return Task::ready(Ok(Navigated::No));
15481        };
15482
15483        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15484            return Task::ready(Ok(Navigated::No));
15485        };
15486
15487        cx.spawn_in(window, async move |editor, cx| {
15488            let definitions = definitions.await?;
15489            let navigated = editor
15490                .update_in(cx, |editor, window, cx| {
15491                    editor.navigate_to_hover_links(
15492                        Some(kind),
15493                        definitions
15494                            .into_iter()
15495                            .filter(|location| {
15496                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15497                            })
15498                            .map(HoverLink::Text)
15499                            .collect::<Vec<_>>(),
15500                        split,
15501                        window,
15502                        cx,
15503                    )
15504                })?
15505                .await?;
15506            anyhow::Ok(navigated)
15507        })
15508    }
15509
15510    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15511        let selection = self.selections.newest_anchor();
15512        let head = selection.head();
15513        let tail = selection.tail();
15514
15515        let Some((buffer, start_position)) =
15516            self.buffer.read(cx).text_anchor_for_position(head, cx)
15517        else {
15518            return;
15519        };
15520
15521        let end_position = if head != tail {
15522            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15523                return;
15524            };
15525            Some(pos)
15526        } else {
15527            None
15528        };
15529
15530        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15531            let url = if let Some(end_pos) = end_position {
15532                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15533            } else {
15534                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15535            };
15536
15537            if let Some(url) = url {
15538                editor.update(cx, |_, cx| {
15539                    cx.open_url(&url);
15540                })
15541            } else {
15542                Ok(())
15543            }
15544        });
15545
15546        url_finder.detach();
15547    }
15548
15549    pub fn open_selected_filename(
15550        &mut self,
15551        _: &OpenSelectedFilename,
15552        window: &mut Window,
15553        cx: &mut Context<Self>,
15554    ) {
15555        let Some(workspace) = self.workspace() else {
15556            return;
15557        };
15558
15559        let position = self.selections.newest_anchor().head();
15560
15561        let Some((buffer, buffer_position)) =
15562            self.buffer.read(cx).text_anchor_for_position(position, cx)
15563        else {
15564            return;
15565        };
15566
15567        let project = self.project.clone();
15568
15569        cx.spawn_in(window, async move |_, cx| {
15570            let result = find_file(&buffer, project, buffer_position, cx).await;
15571
15572            if let Some((_, path)) = result {
15573                workspace
15574                    .update_in(cx, |workspace, window, cx| {
15575                        workspace.open_resolved_path(path, window, cx)
15576                    })?
15577                    .await?;
15578            }
15579            anyhow::Ok(())
15580        })
15581        .detach();
15582    }
15583
15584    pub(crate) fn navigate_to_hover_links(
15585        &mut self,
15586        kind: Option<GotoDefinitionKind>,
15587        mut definitions: Vec<HoverLink>,
15588        split: bool,
15589        window: &mut Window,
15590        cx: &mut Context<Editor>,
15591    ) -> Task<Result<Navigated>> {
15592        // If there is one definition, just open it directly
15593        if definitions.len() == 1 {
15594            let definition = definitions.pop().unwrap();
15595
15596            enum TargetTaskResult {
15597                Location(Option<Location>),
15598                AlreadyNavigated,
15599            }
15600
15601            let target_task = match definition {
15602                HoverLink::Text(link) => {
15603                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15604                }
15605                HoverLink::InlayHint(lsp_location, server_id) => {
15606                    let computation =
15607                        self.compute_target_location(lsp_location, server_id, window, cx);
15608                    cx.background_spawn(async move {
15609                        let location = computation.await?;
15610                        Ok(TargetTaskResult::Location(location))
15611                    })
15612                }
15613                HoverLink::Url(url) => {
15614                    cx.open_url(&url);
15615                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15616                }
15617                HoverLink::File(path) => {
15618                    if let Some(workspace) = self.workspace() {
15619                        cx.spawn_in(window, async move |_, cx| {
15620                            workspace
15621                                .update_in(cx, |workspace, window, cx| {
15622                                    workspace.open_resolved_path(path, window, cx)
15623                                })?
15624                                .await
15625                                .map(|_| TargetTaskResult::AlreadyNavigated)
15626                        })
15627                    } else {
15628                        Task::ready(Ok(TargetTaskResult::Location(None)))
15629                    }
15630                }
15631            };
15632            cx.spawn_in(window, async move |editor, cx| {
15633                let target = match target_task.await.context("target resolution task")? {
15634                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15635                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15636                    TargetTaskResult::Location(Some(target)) => target,
15637                };
15638
15639                editor.update_in(cx, |editor, window, cx| {
15640                    let Some(workspace) = editor.workspace() else {
15641                        return Navigated::No;
15642                    };
15643                    let pane = workspace.read(cx).active_pane().clone();
15644
15645                    let range = target.range.to_point(target.buffer.read(cx));
15646                    let range = editor.range_for_match(&range);
15647                    let range = collapse_multiline_range(range);
15648
15649                    if !split
15650                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15651                    {
15652                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15653                    } else {
15654                        window.defer(cx, move |window, cx| {
15655                            let target_editor: Entity<Self> =
15656                                workspace.update(cx, |workspace, cx| {
15657                                    let pane = if split {
15658                                        workspace.adjacent_pane(window, cx)
15659                                    } else {
15660                                        workspace.active_pane().clone()
15661                                    };
15662
15663                                    workspace.open_project_item(
15664                                        pane,
15665                                        target.buffer.clone(),
15666                                        true,
15667                                        true,
15668                                        window,
15669                                        cx,
15670                                    )
15671                                });
15672                            target_editor.update(cx, |target_editor, cx| {
15673                                // When selecting a definition in a different buffer, disable the nav history
15674                                // to avoid creating a history entry at the previous cursor location.
15675                                pane.update(cx, |pane, _| pane.disable_history());
15676                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15677                                pane.update(cx, |pane, _| pane.enable_history());
15678                            });
15679                        });
15680                    }
15681                    Navigated::Yes
15682                })
15683            })
15684        } else if !definitions.is_empty() {
15685            cx.spawn_in(window, async move |editor, cx| {
15686                let (title, location_tasks, workspace) = editor
15687                    .update_in(cx, |editor, window, cx| {
15688                        let tab_kind = match kind {
15689                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15690                            _ => "Definitions",
15691                        };
15692                        let title = definitions
15693                            .iter()
15694                            .find_map(|definition| match definition {
15695                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15696                                    let buffer = origin.buffer.read(cx);
15697                                    format!(
15698                                        "{} for {}",
15699                                        tab_kind,
15700                                        buffer
15701                                            .text_for_range(origin.range.clone())
15702                                            .collect::<String>()
15703                                    )
15704                                }),
15705                                HoverLink::InlayHint(_, _) => None,
15706                                HoverLink::Url(_) => None,
15707                                HoverLink::File(_) => None,
15708                            })
15709                            .unwrap_or(tab_kind.to_string());
15710                        let location_tasks = definitions
15711                            .into_iter()
15712                            .map(|definition| match definition {
15713                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15714                                HoverLink::InlayHint(lsp_location, server_id) => editor
15715                                    .compute_target_location(lsp_location, server_id, window, cx),
15716                                HoverLink::Url(_) => Task::ready(Ok(None)),
15717                                HoverLink::File(_) => Task::ready(Ok(None)),
15718                            })
15719                            .collect::<Vec<_>>();
15720                        (title, location_tasks, editor.workspace().clone())
15721                    })
15722                    .context("location tasks preparation")?;
15723
15724                let locations: Vec<Location> = future::join_all(location_tasks)
15725                    .await
15726                    .into_iter()
15727                    .filter_map(|location| location.transpose())
15728                    .collect::<Result<_>>()
15729                    .context("location tasks")?;
15730
15731                if locations.is_empty() {
15732                    return Ok(Navigated::No);
15733                }
15734
15735                let Some(workspace) = workspace else {
15736                    return Ok(Navigated::No);
15737                };
15738
15739                let opened = workspace
15740                    .update_in(cx, |workspace, window, cx| {
15741                        Self::open_locations_in_multibuffer(
15742                            workspace,
15743                            locations,
15744                            title,
15745                            split,
15746                            MultibufferSelectionMode::First,
15747                            window,
15748                            cx,
15749                        )
15750                    })
15751                    .ok();
15752
15753                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15754            })
15755        } else {
15756            Task::ready(Ok(Navigated::No))
15757        }
15758    }
15759
15760    fn compute_target_location(
15761        &self,
15762        lsp_location: lsp::Location,
15763        server_id: LanguageServerId,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) -> Task<anyhow::Result<Option<Location>>> {
15767        let Some(project) = self.project.clone() else {
15768            return Task::ready(Ok(None));
15769        };
15770
15771        cx.spawn_in(window, async move |editor, cx| {
15772            let location_task = editor.update(cx, |_, cx| {
15773                project.update(cx, |project, cx| {
15774                    let language_server_name = project
15775                        .language_server_statuses(cx)
15776                        .find(|(id, _)| server_id == *id)
15777                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15778                    language_server_name.map(|language_server_name| {
15779                        project.open_local_buffer_via_lsp(
15780                            lsp_location.uri.clone(),
15781                            server_id,
15782                            language_server_name,
15783                            cx,
15784                        )
15785                    })
15786                })
15787            })?;
15788            let location = match location_task {
15789                Some(task) => Some({
15790                    let target_buffer_handle = task.await.context("open local buffer")?;
15791                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15792                        let target_start = target_buffer
15793                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15794                        let target_end = target_buffer
15795                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15796                        target_buffer.anchor_after(target_start)
15797                            ..target_buffer.anchor_before(target_end)
15798                    })?;
15799                    Location {
15800                        buffer: target_buffer_handle,
15801                        range,
15802                    }
15803                }),
15804                None => None,
15805            };
15806            Ok(location)
15807        })
15808    }
15809
15810    pub fn find_all_references(
15811        &mut self,
15812        _: &FindAllReferences,
15813        window: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) -> Option<Task<Result<Navigated>>> {
15816        let selection = self.selections.newest::<usize>(cx);
15817        let multi_buffer = self.buffer.read(cx);
15818        let head = selection.head();
15819
15820        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15821        let head_anchor = multi_buffer_snapshot.anchor_at(
15822            head,
15823            if head < selection.tail() {
15824                Bias::Right
15825            } else {
15826                Bias::Left
15827            },
15828        );
15829
15830        match self
15831            .find_all_references_task_sources
15832            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15833        {
15834            Ok(_) => {
15835                log::info!(
15836                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15837                );
15838                return None;
15839            }
15840            Err(i) => {
15841                self.find_all_references_task_sources.insert(i, head_anchor);
15842            }
15843        }
15844
15845        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15846        let workspace = self.workspace()?;
15847        let project = workspace.read(cx).project().clone();
15848        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15849        Some(cx.spawn_in(window, async move |editor, cx| {
15850            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15851                if let Ok(i) = editor
15852                    .find_all_references_task_sources
15853                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15854                {
15855                    editor.find_all_references_task_sources.remove(i);
15856                }
15857            });
15858
15859            let locations = references.await?;
15860            if locations.is_empty() {
15861                return anyhow::Ok(Navigated::No);
15862            }
15863
15864            workspace.update_in(cx, |workspace, window, cx| {
15865                let title = locations
15866                    .first()
15867                    .as_ref()
15868                    .map(|location| {
15869                        let buffer = location.buffer.read(cx);
15870                        format!(
15871                            "References to `{}`",
15872                            buffer
15873                                .text_for_range(location.range.clone())
15874                                .collect::<String>()
15875                        )
15876                    })
15877                    .unwrap();
15878                Self::open_locations_in_multibuffer(
15879                    workspace,
15880                    locations,
15881                    title,
15882                    false,
15883                    MultibufferSelectionMode::First,
15884                    window,
15885                    cx,
15886                );
15887                Navigated::Yes
15888            })
15889        }))
15890    }
15891
15892    /// Opens a multibuffer with the given project locations in it
15893    pub fn open_locations_in_multibuffer(
15894        workspace: &mut Workspace,
15895        mut locations: Vec<Location>,
15896        title: String,
15897        split: bool,
15898        multibuffer_selection_mode: MultibufferSelectionMode,
15899        window: &mut Window,
15900        cx: &mut Context<Workspace>,
15901    ) {
15902        if locations.is_empty() {
15903            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15904            return;
15905        }
15906
15907        // If there are multiple definitions, open them in a multibuffer
15908        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15909        let mut locations = locations.into_iter().peekable();
15910        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15911        let capability = workspace.project().read(cx).capability();
15912
15913        let excerpt_buffer = cx.new(|cx| {
15914            let mut multibuffer = MultiBuffer::new(capability);
15915            while let Some(location) = locations.next() {
15916                let buffer = location.buffer.read(cx);
15917                let mut ranges_for_buffer = Vec::new();
15918                let range = location.range.to_point(buffer);
15919                ranges_for_buffer.push(range.clone());
15920
15921                while let Some(next_location) = locations.peek() {
15922                    if next_location.buffer == location.buffer {
15923                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15924                        locations.next();
15925                    } else {
15926                        break;
15927                    }
15928                }
15929
15930                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15931                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15932                    PathKey::for_buffer(&location.buffer, cx),
15933                    location.buffer.clone(),
15934                    ranges_for_buffer,
15935                    DEFAULT_MULTIBUFFER_CONTEXT,
15936                    cx,
15937                );
15938                ranges.extend(new_ranges)
15939            }
15940
15941            multibuffer.with_title(title)
15942        });
15943
15944        let editor = cx.new(|cx| {
15945            Editor::for_multibuffer(
15946                excerpt_buffer,
15947                Some(workspace.project().clone()),
15948                window,
15949                cx,
15950            )
15951        });
15952        editor.update(cx, |editor, cx| {
15953            match multibuffer_selection_mode {
15954                MultibufferSelectionMode::First => {
15955                    if let Some(first_range) = ranges.first() {
15956                        editor.change_selections(
15957                            SelectionEffects::no_scroll(),
15958                            window,
15959                            cx,
15960                            |selections| {
15961                                selections.clear_disjoint();
15962                                selections
15963                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15964                            },
15965                        );
15966                    }
15967                    editor.highlight_background::<Self>(
15968                        &ranges,
15969                        |theme| theme.colors().editor_highlighted_line_background,
15970                        cx,
15971                    );
15972                }
15973                MultibufferSelectionMode::All => {
15974                    editor.change_selections(
15975                        SelectionEffects::no_scroll(),
15976                        window,
15977                        cx,
15978                        |selections| {
15979                            selections.clear_disjoint();
15980                            selections.select_anchor_ranges(ranges);
15981                        },
15982                    );
15983                }
15984            }
15985            editor.register_buffers_with_language_servers(cx);
15986        });
15987
15988        let item = Box::new(editor);
15989        let item_id = item.item_id();
15990
15991        if split {
15992            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15993        } else {
15994            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15995                let (preview_item_id, preview_item_idx) =
15996                    workspace.active_pane().read_with(cx, |pane, _| {
15997                        (pane.preview_item_id(), pane.preview_item_idx())
15998                    });
15999
16000                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16001
16002                if let Some(preview_item_id) = preview_item_id {
16003                    workspace.active_pane().update(cx, |pane, cx| {
16004                        pane.remove_item(preview_item_id, false, false, window, cx);
16005                    });
16006                }
16007            } else {
16008                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16009            }
16010        }
16011        workspace.active_pane().update(cx, |pane, cx| {
16012            pane.set_preview_item_id(Some(item_id), cx);
16013        });
16014    }
16015
16016    pub fn rename(
16017        &mut self,
16018        _: &Rename,
16019        window: &mut Window,
16020        cx: &mut Context<Self>,
16021    ) -> Option<Task<Result<()>>> {
16022        use language::ToOffset as _;
16023
16024        let provider = self.semantics_provider.clone()?;
16025        let selection = self.selections.newest_anchor().clone();
16026        let (cursor_buffer, cursor_buffer_position) = self
16027            .buffer
16028            .read(cx)
16029            .text_anchor_for_position(selection.head(), cx)?;
16030        let (tail_buffer, cursor_buffer_position_end) = self
16031            .buffer
16032            .read(cx)
16033            .text_anchor_for_position(selection.tail(), cx)?;
16034        if tail_buffer != cursor_buffer {
16035            return None;
16036        }
16037
16038        let snapshot = cursor_buffer.read(cx).snapshot();
16039        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16040        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16041        let prepare_rename = provider
16042            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16043            .unwrap_or_else(|| Task::ready(Ok(None)));
16044        drop(snapshot);
16045
16046        Some(cx.spawn_in(window, async move |this, cx| {
16047            let rename_range = if let Some(range) = prepare_rename.await? {
16048                Some(range)
16049            } else {
16050                this.update(cx, |this, cx| {
16051                    let buffer = this.buffer.read(cx).snapshot(cx);
16052                    let mut buffer_highlights = this
16053                        .document_highlights_for_position(selection.head(), &buffer)
16054                        .filter(|highlight| {
16055                            highlight.start.excerpt_id == selection.head().excerpt_id
16056                                && highlight.end.excerpt_id == selection.head().excerpt_id
16057                        });
16058                    buffer_highlights
16059                        .next()
16060                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16061                })?
16062            };
16063            if let Some(rename_range) = rename_range {
16064                this.update_in(cx, |this, window, cx| {
16065                    let snapshot = cursor_buffer.read(cx).snapshot();
16066                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16067                    let cursor_offset_in_rename_range =
16068                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16069                    let cursor_offset_in_rename_range_end =
16070                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16071
16072                    this.take_rename(false, window, cx);
16073                    let buffer = this.buffer.read(cx).read(cx);
16074                    let cursor_offset = selection.head().to_offset(&buffer);
16075                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16076                    let rename_end = rename_start + rename_buffer_range.len();
16077                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16078                    let mut old_highlight_id = None;
16079                    let old_name: Arc<str> = buffer
16080                        .chunks(rename_start..rename_end, true)
16081                        .map(|chunk| {
16082                            if old_highlight_id.is_none() {
16083                                old_highlight_id = chunk.syntax_highlight_id;
16084                            }
16085                            chunk.text
16086                        })
16087                        .collect::<String>()
16088                        .into();
16089
16090                    drop(buffer);
16091
16092                    // Position the selection in the rename editor so that it matches the current selection.
16093                    this.show_local_selections = false;
16094                    let rename_editor = cx.new(|cx| {
16095                        let mut editor = Editor::single_line(window, cx);
16096                        editor.buffer.update(cx, |buffer, cx| {
16097                            buffer.edit([(0..0, old_name.clone())], None, cx)
16098                        });
16099                        let rename_selection_range = match cursor_offset_in_rename_range
16100                            .cmp(&cursor_offset_in_rename_range_end)
16101                        {
16102                            Ordering::Equal => {
16103                                editor.select_all(&SelectAll, window, cx);
16104                                return editor;
16105                            }
16106                            Ordering::Less => {
16107                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16108                            }
16109                            Ordering::Greater => {
16110                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16111                            }
16112                        };
16113                        if rename_selection_range.end > old_name.len() {
16114                            editor.select_all(&SelectAll, window, cx);
16115                        } else {
16116                            editor.change_selections(Default::default(), window, cx, |s| {
16117                                s.select_ranges([rename_selection_range]);
16118                            });
16119                        }
16120                        editor
16121                    });
16122                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16123                        if e == &EditorEvent::Focused {
16124                            cx.emit(EditorEvent::FocusedIn)
16125                        }
16126                    })
16127                    .detach();
16128
16129                    let write_highlights =
16130                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16131                    let read_highlights =
16132                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16133                    let ranges = write_highlights
16134                        .iter()
16135                        .flat_map(|(_, ranges)| ranges.iter())
16136                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16137                        .cloned()
16138                        .collect();
16139
16140                    this.highlight_text::<Rename>(
16141                        ranges,
16142                        HighlightStyle {
16143                            fade_out: Some(0.6),
16144                            ..Default::default()
16145                        },
16146                        cx,
16147                    );
16148                    let rename_focus_handle = rename_editor.focus_handle(cx);
16149                    window.focus(&rename_focus_handle);
16150                    let block_id = this.insert_blocks(
16151                        [BlockProperties {
16152                            style: BlockStyle::Flex,
16153                            placement: BlockPlacement::Below(range.start),
16154                            height: Some(1),
16155                            render: Arc::new({
16156                                let rename_editor = rename_editor.clone();
16157                                move |cx: &mut BlockContext| {
16158                                    let mut text_style = cx.editor_style.text.clone();
16159                                    if let Some(highlight_style) = old_highlight_id
16160                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16161                                    {
16162                                        text_style = text_style.highlight(highlight_style);
16163                                    }
16164                                    div()
16165                                        .block_mouse_except_scroll()
16166                                        .pl(cx.anchor_x)
16167                                        .child(EditorElement::new(
16168                                            &rename_editor,
16169                                            EditorStyle {
16170                                                background: cx.theme().system().transparent,
16171                                                local_player: cx.editor_style.local_player,
16172                                                text: text_style,
16173                                                scrollbar_width: cx.editor_style.scrollbar_width,
16174                                                syntax: cx.editor_style.syntax.clone(),
16175                                                status: cx.editor_style.status.clone(),
16176                                                inlay_hints_style: HighlightStyle {
16177                                                    font_weight: Some(FontWeight::BOLD),
16178                                                    ..make_inlay_hints_style(cx.app)
16179                                                },
16180                                                inline_completion_styles: make_suggestion_styles(
16181                                                    cx.app,
16182                                                ),
16183                                                ..EditorStyle::default()
16184                                            },
16185                                        ))
16186                                        .into_any_element()
16187                                }
16188                            }),
16189                            priority: 0,
16190                        }],
16191                        Some(Autoscroll::fit()),
16192                        cx,
16193                    )[0];
16194                    this.pending_rename = Some(RenameState {
16195                        range,
16196                        old_name,
16197                        editor: rename_editor,
16198                        block_id,
16199                    });
16200                })?;
16201            }
16202
16203            Ok(())
16204        }))
16205    }
16206
16207    pub fn confirm_rename(
16208        &mut self,
16209        _: &ConfirmRename,
16210        window: &mut Window,
16211        cx: &mut Context<Self>,
16212    ) -> Option<Task<Result<()>>> {
16213        let rename = self.take_rename(false, window, cx)?;
16214        let workspace = self.workspace()?.downgrade();
16215        let (buffer, start) = self
16216            .buffer
16217            .read(cx)
16218            .text_anchor_for_position(rename.range.start, cx)?;
16219        let (end_buffer, _) = self
16220            .buffer
16221            .read(cx)
16222            .text_anchor_for_position(rename.range.end, cx)?;
16223        if buffer != end_buffer {
16224            return None;
16225        }
16226
16227        let old_name = rename.old_name;
16228        let new_name = rename.editor.read(cx).text(cx);
16229
16230        let rename = self.semantics_provider.as_ref()?.perform_rename(
16231            &buffer,
16232            start,
16233            new_name.clone(),
16234            cx,
16235        )?;
16236
16237        Some(cx.spawn_in(window, async move |editor, cx| {
16238            let project_transaction = rename.await?;
16239            Self::open_project_transaction(
16240                &editor,
16241                workspace,
16242                project_transaction,
16243                format!("Rename: {}{}", old_name, new_name),
16244                cx,
16245            )
16246            .await?;
16247
16248            editor.update(cx, |editor, cx| {
16249                editor.refresh_document_highlights(cx);
16250            })?;
16251            Ok(())
16252        }))
16253    }
16254
16255    fn take_rename(
16256        &mut self,
16257        moving_cursor: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Option<RenameState> {
16261        let rename = self.pending_rename.take()?;
16262        if rename.editor.focus_handle(cx).is_focused(window) {
16263            window.focus(&self.focus_handle);
16264        }
16265
16266        self.remove_blocks(
16267            [rename.block_id].into_iter().collect(),
16268            Some(Autoscroll::fit()),
16269            cx,
16270        );
16271        self.clear_highlights::<Rename>(cx);
16272        self.show_local_selections = true;
16273
16274        if moving_cursor {
16275            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16276                editor.selections.newest::<usize>(cx).head()
16277            });
16278
16279            // Update the selection to match the position of the selection inside
16280            // the rename editor.
16281            let snapshot = self.buffer.read(cx).read(cx);
16282            let rename_range = rename.range.to_offset(&snapshot);
16283            let cursor_in_editor = snapshot
16284                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16285                .min(rename_range.end);
16286            drop(snapshot);
16287
16288            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16289                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16290            });
16291        } else {
16292            self.refresh_document_highlights(cx);
16293        }
16294
16295        Some(rename)
16296    }
16297
16298    pub fn pending_rename(&self) -> Option<&RenameState> {
16299        self.pending_rename.as_ref()
16300    }
16301
16302    fn format(
16303        &mut self,
16304        _: &Format,
16305        window: &mut Window,
16306        cx: &mut Context<Self>,
16307    ) -> Option<Task<Result<()>>> {
16308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16309
16310        let project = match &self.project {
16311            Some(project) => project.clone(),
16312            None => return None,
16313        };
16314
16315        Some(self.perform_format(
16316            project,
16317            FormatTrigger::Manual,
16318            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16319            window,
16320            cx,
16321        ))
16322    }
16323
16324    fn format_selections(
16325        &mut self,
16326        _: &FormatSelections,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) -> Option<Task<Result<()>>> {
16330        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16331
16332        let project = match &self.project {
16333            Some(project) => project.clone(),
16334            None => return None,
16335        };
16336
16337        let ranges = self
16338            .selections
16339            .all_adjusted(cx)
16340            .into_iter()
16341            .map(|selection| selection.range())
16342            .collect_vec();
16343
16344        Some(self.perform_format(
16345            project,
16346            FormatTrigger::Manual,
16347            FormatTarget::Ranges(ranges),
16348            window,
16349            cx,
16350        ))
16351    }
16352
16353    fn perform_format(
16354        &mut self,
16355        project: Entity<Project>,
16356        trigger: FormatTrigger,
16357        target: FormatTarget,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<()>> {
16361        let buffer = self.buffer.clone();
16362        let (buffers, target) = match target {
16363            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16364            FormatTarget::Ranges(selection_ranges) => {
16365                let multi_buffer = buffer.read(cx);
16366                let snapshot = multi_buffer.read(cx);
16367                let mut buffers = HashSet::default();
16368                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16369                    BTreeMap::new();
16370                for selection_range in selection_ranges {
16371                    for (buffer, buffer_range, _) in
16372                        snapshot.range_to_buffer_ranges(selection_range)
16373                    {
16374                        let buffer_id = buffer.remote_id();
16375                        let start = buffer.anchor_before(buffer_range.start);
16376                        let end = buffer.anchor_after(buffer_range.end);
16377                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16378                        buffer_id_to_ranges
16379                            .entry(buffer_id)
16380                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16381                            .or_insert_with(|| vec![start..end]);
16382                    }
16383                }
16384                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16385            }
16386        };
16387
16388        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16389        let selections_prev = transaction_id_prev
16390            .and_then(|transaction_id_prev| {
16391                // default to selections as they were after the last edit, if we have them,
16392                // instead of how they are now.
16393                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16394                // will take you back to where you made the last edit, instead of staying where you scrolled
16395                self.selection_history
16396                    .transaction(transaction_id_prev)
16397                    .map(|t| t.0.clone())
16398            })
16399            .unwrap_or_else(|| {
16400                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16401                self.selections.disjoint_anchors()
16402            });
16403
16404        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16405        let format = project.update(cx, |project, cx| {
16406            project.format(buffers, target, true, trigger, cx)
16407        });
16408
16409        cx.spawn_in(window, async move |editor, cx| {
16410            let transaction = futures::select_biased! {
16411                transaction = format.log_err().fuse() => transaction,
16412                () = timeout => {
16413                    log::warn!("timed out waiting for formatting");
16414                    None
16415                }
16416            };
16417
16418            buffer
16419                .update(cx, |buffer, cx| {
16420                    if let Some(transaction) = transaction {
16421                        if !buffer.is_singleton() {
16422                            buffer.push_transaction(&transaction.0, cx);
16423                        }
16424                    }
16425                    cx.notify();
16426                })
16427                .ok();
16428
16429            if let Some(transaction_id_now) =
16430                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16431            {
16432                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16433                if has_new_transaction {
16434                    _ = editor.update(cx, |editor, _| {
16435                        editor
16436                            .selection_history
16437                            .insert_transaction(transaction_id_now, selections_prev);
16438                    });
16439                }
16440            }
16441
16442            Ok(())
16443        })
16444    }
16445
16446    fn organize_imports(
16447        &mut self,
16448        _: &OrganizeImports,
16449        window: &mut Window,
16450        cx: &mut Context<Self>,
16451    ) -> Option<Task<Result<()>>> {
16452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16453        let project = match &self.project {
16454            Some(project) => project.clone(),
16455            None => return None,
16456        };
16457        Some(self.perform_code_action_kind(
16458            project,
16459            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16460            window,
16461            cx,
16462        ))
16463    }
16464
16465    fn perform_code_action_kind(
16466        &mut self,
16467        project: Entity<Project>,
16468        kind: CodeActionKind,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) -> Task<Result<()>> {
16472        let buffer = self.buffer.clone();
16473        let buffers = buffer.read(cx).all_buffers();
16474        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16475        let apply_action = project.update(cx, |project, cx| {
16476            project.apply_code_action_kind(buffers, kind, true, cx)
16477        });
16478        cx.spawn_in(window, async move |_, cx| {
16479            let transaction = futures::select_biased! {
16480                () = timeout => {
16481                    log::warn!("timed out waiting for executing code action");
16482                    None
16483                }
16484                transaction = apply_action.log_err().fuse() => transaction,
16485            };
16486            buffer
16487                .update(cx, |buffer, cx| {
16488                    // check if we need this
16489                    if let Some(transaction) = transaction {
16490                        if !buffer.is_singleton() {
16491                            buffer.push_transaction(&transaction.0, cx);
16492                        }
16493                    }
16494                    cx.notify();
16495                })
16496                .ok();
16497            Ok(())
16498        })
16499    }
16500
16501    pub fn restart_language_server(
16502        &mut self,
16503        _: &RestartLanguageServer,
16504        _: &mut Window,
16505        cx: &mut Context<Self>,
16506    ) {
16507        if let Some(project) = self.project.clone() {
16508            self.buffer.update(cx, |multi_buffer, cx| {
16509                project.update(cx, |project, cx| {
16510                    project.restart_language_servers_for_buffers(
16511                        multi_buffer.all_buffers().into_iter().collect(),
16512                        HashSet::default(),
16513                        cx,
16514                    );
16515                });
16516            })
16517        }
16518    }
16519
16520    pub fn stop_language_server(
16521        &mut self,
16522        _: &StopLanguageServer,
16523        _: &mut Window,
16524        cx: &mut Context<Self>,
16525    ) {
16526        if let Some(project) = self.project.clone() {
16527            self.buffer.update(cx, |multi_buffer, cx| {
16528                project.update(cx, |project, cx| {
16529                    project.stop_language_servers_for_buffers(
16530                        multi_buffer.all_buffers().into_iter().collect(),
16531                        HashSet::default(),
16532                        cx,
16533                    );
16534                    cx.emit(project::Event::RefreshInlayHints);
16535                });
16536            });
16537        }
16538    }
16539
16540    fn cancel_language_server_work(
16541        workspace: &mut Workspace,
16542        _: &actions::CancelLanguageServerWork,
16543        _: &mut Window,
16544        cx: &mut Context<Workspace>,
16545    ) {
16546        let project = workspace.project();
16547        let buffers = workspace
16548            .active_item(cx)
16549            .and_then(|item| item.act_as::<Editor>(cx))
16550            .map_or(HashSet::default(), |editor| {
16551                editor.read(cx).buffer.read(cx).all_buffers()
16552            });
16553        project.update(cx, |project, cx| {
16554            project.cancel_language_server_work_for_buffers(buffers, cx);
16555        });
16556    }
16557
16558    fn show_character_palette(
16559        &mut self,
16560        _: &ShowCharacterPalette,
16561        window: &mut Window,
16562        _: &mut Context<Self>,
16563    ) {
16564        window.show_character_palette();
16565    }
16566
16567    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16568        if !self.diagnostics_enabled() {
16569            return;
16570        }
16571
16572        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16573            let buffer = self.buffer.read(cx).snapshot(cx);
16574            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16575            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16576            let is_valid = buffer
16577                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16578                .any(|entry| {
16579                    entry.diagnostic.is_primary
16580                        && !entry.range.is_empty()
16581                        && entry.range.start == primary_range_start
16582                        && entry.diagnostic.message == active_diagnostics.active_message
16583                });
16584
16585            if !is_valid {
16586                self.dismiss_diagnostics(cx);
16587            }
16588        }
16589    }
16590
16591    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16592        match &self.active_diagnostics {
16593            ActiveDiagnostic::Group(group) => Some(group),
16594            _ => None,
16595        }
16596    }
16597
16598    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16599        if !self.diagnostics_enabled() {
16600            return;
16601        }
16602        self.dismiss_diagnostics(cx);
16603        self.active_diagnostics = ActiveDiagnostic::All;
16604    }
16605
16606    fn activate_diagnostics(
16607        &mut self,
16608        buffer_id: BufferId,
16609        diagnostic: DiagnosticEntry<usize>,
16610        window: &mut Window,
16611        cx: &mut Context<Self>,
16612    ) {
16613        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16614            return;
16615        }
16616        self.dismiss_diagnostics(cx);
16617        let snapshot = self.snapshot(window, cx);
16618        let buffer = self.buffer.read(cx).snapshot(cx);
16619        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16620            return;
16621        };
16622
16623        let diagnostic_group = buffer
16624            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16625            .collect::<Vec<_>>();
16626
16627        let blocks =
16628            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16629
16630        let blocks = self.display_map.update(cx, |display_map, cx| {
16631            display_map.insert_blocks(blocks, cx).into_iter().collect()
16632        });
16633        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16634            active_range: buffer.anchor_before(diagnostic.range.start)
16635                ..buffer.anchor_after(diagnostic.range.end),
16636            active_message: diagnostic.diagnostic.message.clone(),
16637            group_id: diagnostic.diagnostic.group_id,
16638            blocks,
16639        });
16640        cx.notify();
16641    }
16642
16643    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16644        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16645            return;
16646        };
16647
16648        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16649        if let ActiveDiagnostic::Group(group) = prev {
16650            self.display_map.update(cx, |display_map, cx| {
16651                display_map.remove_blocks(group.blocks, cx);
16652            });
16653            cx.notify();
16654        }
16655    }
16656
16657    /// Disable inline diagnostics rendering for this editor.
16658    pub fn disable_inline_diagnostics(&mut self) {
16659        self.inline_diagnostics_enabled = false;
16660        self.inline_diagnostics_update = Task::ready(());
16661        self.inline_diagnostics.clear();
16662    }
16663
16664    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16665        self.diagnostics_enabled = false;
16666        self.dismiss_diagnostics(cx);
16667        self.inline_diagnostics_update = Task::ready(());
16668        self.inline_diagnostics.clear();
16669    }
16670
16671    pub fn diagnostics_enabled(&self) -> bool {
16672        self.diagnostics_enabled && self.mode.is_full()
16673    }
16674
16675    pub fn inline_diagnostics_enabled(&self) -> bool {
16676        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16677    }
16678
16679    pub fn show_inline_diagnostics(&self) -> bool {
16680        self.show_inline_diagnostics
16681    }
16682
16683    pub fn toggle_inline_diagnostics(
16684        &mut self,
16685        _: &ToggleInlineDiagnostics,
16686        window: &mut Window,
16687        cx: &mut Context<Editor>,
16688    ) {
16689        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16690        self.refresh_inline_diagnostics(false, window, cx);
16691    }
16692
16693    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16694        self.diagnostics_max_severity = severity;
16695        self.display_map.update(cx, |display_map, _| {
16696            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16697        });
16698    }
16699
16700    pub fn toggle_diagnostics(
16701        &mut self,
16702        _: &ToggleDiagnostics,
16703        window: &mut Window,
16704        cx: &mut Context<Editor>,
16705    ) {
16706        if !self.diagnostics_enabled() {
16707            return;
16708        }
16709
16710        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16711            EditorSettings::get_global(cx)
16712                .diagnostics_max_severity
16713                .filter(|severity| severity != &DiagnosticSeverity::Off)
16714                .unwrap_or(DiagnosticSeverity::Hint)
16715        } else {
16716            DiagnosticSeverity::Off
16717        };
16718        self.set_max_diagnostics_severity(new_severity, cx);
16719        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16720            self.active_diagnostics = ActiveDiagnostic::None;
16721            self.inline_diagnostics_update = Task::ready(());
16722            self.inline_diagnostics.clear();
16723        } else {
16724            self.refresh_inline_diagnostics(false, window, cx);
16725        }
16726
16727        cx.notify();
16728    }
16729
16730    pub fn toggle_minimap(
16731        &mut self,
16732        _: &ToggleMinimap,
16733        window: &mut Window,
16734        cx: &mut Context<Editor>,
16735    ) {
16736        if self.supports_minimap(cx) {
16737            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16738        }
16739    }
16740
16741    fn refresh_inline_diagnostics(
16742        &mut self,
16743        debounce: bool,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) {
16747        let max_severity = ProjectSettings::get_global(cx)
16748            .diagnostics
16749            .inline
16750            .max_severity
16751            .unwrap_or(self.diagnostics_max_severity);
16752
16753        if !self.inline_diagnostics_enabled()
16754            || !self.show_inline_diagnostics
16755            || max_severity == DiagnosticSeverity::Off
16756        {
16757            self.inline_diagnostics_update = Task::ready(());
16758            self.inline_diagnostics.clear();
16759            return;
16760        }
16761
16762        let debounce_ms = ProjectSettings::get_global(cx)
16763            .diagnostics
16764            .inline
16765            .update_debounce_ms;
16766        let debounce = if debounce && debounce_ms > 0 {
16767            Some(Duration::from_millis(debounce_ms))
16768        } else {
16769            None
16770        };
16771        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16772            if let Some(debounce) = debounce {
16773                cx.background_executor().timer(debounce).await;
16774            }
16775            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16776                editor
16777                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16778                    .ok()
16779            }) else {
16780                return;
16781            };
16782
16783            let new_inline_diagnostics = cx
16784                .background_spawn(async move {
16785                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16786                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16787                        let message = diagnostic_entry
16788                            .diagnostic
16789                            .message
16790                            .split_once('\n')
16791                            .map(|(line, _)| line)
16792                            .map(SharedString::new)
16793                            .unwrap_or_else(|| {
16794                                SharedString::from(diagnostic_entry.diagnostic.message)
16795                            });
16796                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16797                        let (Ok(i) | Err(i)) = inline_diagnostics
16798                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16799                        inline_diagnostics.insert(
16800                            i,
16801                            (
16802                                start_anchor,
16803                                InlineDiagnostic {
16804                                    message,
16805                                    group_id: diagnostic_entry.diagnostic.group_id,
16806                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16807                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16808                                    severity: diagnostic_entry.diagnostic.severity,
16809                                },
16810                            ),
16811                        );
16812                    }
16813                    inline_diagnostics
16814                })
16815                .await;
16816
16817            editor
16818                .update(cx, |editor, cx| {
16819                    editor.inline_diagnostics = new_inline_diagnostics;
16820                    cx.notify();
16821                })
16822                .ok();
16823        });
16824    }
16825
16826    fn pull_diagnostics(
16827        &mut self,
16828        buffer_id: Option<BufferId>,
16829        window: &Window,
16830        cx: &mut Context<Self>,
16831    ) -> Option<()> {
16832        if !self.mode().is_full() {
16833            return None;
16834        }
16835        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16836            .diagnostics
16837            .lsp_pull_diagnostics;
16838        if !pull_diagnostics_settings.enabled {
16839            return None;
16840        }
16841        let project = self.project.as_ref()?.downgrade();
16842        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16843        let mut buffers = self.buffer.read(cx).all_buffers();
16844        if let Some(buffer_id) = buffer_id {
16845            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16846        }
16847
16848        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16849            cx.background_executor().timer(debounce).await;
16850
16851            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16852                buffers
16853                    .into_iter()
16854                    .filter_map(|buffer| {
16855                        project
16856                            .update(cx, |project, cx| {
16857                                project.lsp_store().update(cx, |lsp_store, cx| {
16858                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16859                                })
16860                            })
16861                            .ok()
16862                    })
16863                    .collect::<FuturesUnordered<_>>()
16864            }) else {
16865                return;
16866            };
16867
16868            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16869                match pull_task {
16870                    Ok(()) => {
16871                        if editor
16872                            .update_in(cx, |editor, window, cx| {
16873                                editor.update_diagnostics_state(window, cx);
16874                            })
16875                            .is_err()
16876                        {
16877                            return;
16878                        }
16879                    }
16880                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16881                }
16882            }
16883        });
16884
16885        Some(())
16886    }
16887
16888    pub fn set_selections_from_remote(
16889        &mut self,
16890        selections: Vec<Selection<Anchor>>,
16891        pending_selection: Option<Selection<Anchor>>,
16892        window: &mut Window,
16893        cx: &mut Context<Self>,
16894    ) {
16895        let old_cursor_position = self.selections.newest_anchor().head();
16896        self.selections.change_with(cx, |s| {
16897            s.select_anchors(selections);
16898            if let Some(pending_selection) = pending_selection {
16899                s.set_pending(pending_selection, SelectMode::Character);
16900            } else {
16901                s.clear_pending();
16902            }
16903        });
16904        self.selections_did_change(
16905            false,
16906            &old_cursor_position,
16907            SelectionEffects::default(),
16908            window,
16909            cx,
16910        );
16911    }
16912
16913    pub fn transact(
16914        &mut self,
16915        window: &mut Window,
16916        cx: &mut Context<Self>,
16917        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16918    ) -> Option<TransactionId> {
16919        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16920            this.start_transaction_at(Instant::now(), window, cx);
16921            update(this, window, cx);
16922            this.end_transaction_at(Instant::now(), cx)
16923        })
16924    }
16925
16926    pub fn start_transaction_at(
16927        &mut self,
16928        now: Instant,
16929        window: &mut Window,
16930        cx: &mut Context<Self>,
16931    ) {
16932        self.end_selection(window, cx);
16933        if let Some(tx_id) = self
16934            .buffer
16935            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16936        {
16937            self.selection_history
16938                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16939            cx.emit(EditorEvent::TransactionBegun {
16940                transaction_id: tx_id,
16941            })
16942        }
16943    }
16944
16945    pub fn end_transaction_at(
16946        &mut self,
16947        now: Instant,
16948        cx: &mut Context<Self>,
16949    ) -> Option<TransactionId> {
16950        if let Some(transaction_id) = self
16951            .buffer
16952            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16953        {
16954            if let Some((_, end_selections)) =
16955                self.selection_history.transaction_mut(transaction_id)
16956            {
16957                *end_selections = Some(self.selections.disjoint_anchors());
16958            } else {
16959                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16960            }
16961
16962            cx.emit(EditorEvent::Edited { transaction_id });
16963            Some(transaction_id)
16964        } else {
16965            None
16966        }
16967    }
16968
16969    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16970        if self.selection_mark_mode {
16971            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16972                s.move_with(|_, sel| {
16973                    sel.collapse_to(sel.head(), SelectionGoal::None);
16974                });
16975            })
16976        }
16977        self.selection_mark_mode = true;
16978        cx.notify();
16979    }
16980
16981    pub fn swap_selection_ends(
16982        &mut self,
16983        _: &actions::SwapSelectionEnds,
16984        window: &mut Window,
16985        cx: &mut Context<Self>,
16986    ) {
16987        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16988            s.move_with(|_, sel| {
16989                if sel.start != sel.end {
16990                    sel.reversed = !sel.reversed
16991                }
16992            });
16993        });
16994        self.request_autoscroll(Autoscroll::newest(), cx);
16995        cx.notify();
16996    }
16997
16998    pub fn toggle_focus(
16999        workspace: &mut Workspace,
17000        _: &actions::ToggleFocus,
17001        window: &mut Window,
17002        cx: &mut Context<Workspace>,
17003    ) {
17004        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17005            return;
17006        };
17007        workspace.activate_item(&item, true, true, window, cx);
17008    }
17009
17010    pub fn toggle_fold(
17011        &mut self,
17012        _: &actions::ToggleFold,
17013        window: &mut Window,
17014        cx: &mut Context<Self>,
17015    ) {
17016        if self.is_singleton(cx) {
17017            let selection = self.selections.newest::<Point>(cx);
17018
17019            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17020            let range = if selection.is_empty() {
17021                let point = selection.head().to_display_point(&display_map);
17022                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17023                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17024                    .to_point(&display_map);
17025                start..end
17026            } else {
17027                selection.range()
17028            };
17029            if display_map.folds_in_range(range).next().is_some() {
17030                self.unfold_lines(&Default::default(), window, cx)
17031            } else {
17032                self.fold(&Default::default(), window, cx)
17033            }
17034        } else {
17035            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17036            let buffer_ids: HashSet<_> = self
17037                .selections
17038                .disjoint_anchor_ranges()
17039                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17040                .collect();
17041
17042            let should_unfold = buffer_ids
17043                .iter()
17044                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17045
17046            for buffer_id in buffer_ids {
17047                if should_unfold {
17048                    self.unfold_buffer(buffer_id, cx);
17049                } else {
17050                    self.fold_buffer(buffer_id, cx);
17051                }
17052            }
17053        }
17054    }
17055
17056    pub fn toggle_fold_recursive(
17057        &mut self,
17058        _: &actions::ToggleFoldRecursive,
17059        window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) {
17062        let selection = self.selections.newest::<Point>(cx);
17063
17064        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17065        let range = if selection.is_empty() {
17066            let point = selection.head().to_display_point(&display_map);
17067            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17068            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17069                .to_point(&display_map);
17070            start..end
17071        } else {
17072            selection.range()
17073        };
17074        if display_map.folds_in_range(range).next().is_some() {
17075            self.unfold_recursive(&Default::default(), window, cx)
17076        } else {
17077            self.fold_recursive(&Default::default(), window, cx)
17078        }
17079    }
17080
17081    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17082        if self.is_singleton(cx) {
17083            let mut to_fold = Vec::new();
17084            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17085            let selections = self.selections.all_adjusted(cx);
17086
17087            for selection in selections {
17088                let range = selection.range().sorted();
17089                let buffer_start_row = range.start.row;
17090
17091                if range.start.row != range.end.row {
17092                    let mut found = false;
17093                    let mut row = range.start.row;
17094                    while row <= range.end.row {
17095                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17096                        {
17097                            found = true;
17098                            row = crease.range().end.row + 1;
17099                            to_fold.push(crease);
17100                        } else {
17101                            row += 1
17102                        }
17103                    }
17104                    if found {
17105                        continue;
17106                    }
17107                }
17108
17109                for row in (0..=range.start.row).rev() {
17110                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17111                        if crease.range().end.row >= buffer_start_row {
17112                            to_fold.push(crease);
17113                            if row <= range.start.row {
17114                                break;
17115                            }
17116                        }
17117                    }
17118                }
17119            }
17120
17121            self.fold_creases(to_fold, true, window, cx);
17122        } else {
17123            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17124            let buffer_ids = self
17125                .selections
17126                .disjoint_anchor_ranges()
17127                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17128                .collect::<HashSet<_>>();
17129            for buffer_id in buffer_ids {
17130                self.fold_buffer(buffer_id, cx);
17131            }
17132        }
17133    }
17134
17135    pub fn toggle_fold_all(
17136        &mut self,
17137        _: &actions::ToggleFoldAll,
17138        window: &mut Window,
17139        cx: &mut Context<Self>,
17140    ) {
17141        if self.buffer.read(cx).is_singleton() {
17142            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17143            let has_folds = display_map
17144                .folds_in_range(0..display_map.buffer_snapshot.len())
17145                .next()
17146                .is_some();
17147
17148            if has_folds {
17149                self.unfold_all(&actions::UnfoldAll, window, cx);
17150            } else {
17151                self.fold_all(&actions::FoldAll, window, cx);
17152            }
17153        } else {
17154            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17155            let should_unfold = buffer_ids
17156                .iter()
17157                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17158
17159            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17160                editor
17161                    .update_in(cx, |editor, _, cx| {
17162                        for buffer_id in buffer_ids {
17163                            if should_unfold {
17164                                editor.unfold_buffer(buffer_id, cx);
17165                            } else {
17166                                editor.fold_buffer(buffer_id, cx);
17167                            }
17168                        }
17169                    })
17170                    .ok();
17171            });
17172        }
17173    }
17174
17175    fn fold_at_level(
17176        &mut self,
17177        fold_at: &FoldAtLevel,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) {
17181        if !self.buffer.read(cx).is_singleton() {
17182            return;
17183        }
17184
17185        let fold_at_level = fold_at.0;
17186        let snapshot = self.buffer.read(cx).snapshot(cx);
17187        let mut to_fold = Vec::new();
17188        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17189
17190        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17191            while start_row < end_row {
17192                match self
17193                    .snapshot(window, cx)
17194                    .crease_for_buffer_row(MultiBufferRow(start_row))
17195                {
17196                    Some(crease) => {
17197                        let nested_start_row = crease.range().start.row + 1;
17198                        let nested_end_row = crease.range().end.row;
17199
17200                        if current_level < fold_at_level {
17201                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17202                        } else if current_level == fold_at_level {
17203                            to_fold.push(crease);
17204                        }
17205
17206                        start_row = nested_end_row + 1;
17207                    }
17208                    None => start_row += 1,
17209                }
17210            }
17211        }
17212
17213        self.fold_creases(to_fold, true, window, cx);
17214    }
17215
17216    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17217        if self.buffer.read(cx).is_singleton() {
17218            let mut fold_ranges = Vec::new();
17219            let snapshot = self.buffer.read(cx).snapshot(cx);
17220
17221            for row in 0..snapshot.max_row().0 {
17222                if let Some(foldable_range) = self
17223                    .snapshot(window, cx)
17224                    .crease_for_buffer_row(MultiBufferRow(row))
17225                {
17226                    fold_ranges.push(foldable_range);
17227                }
17228            }
17229
17230            self.fold_creases(fold_ranges, true, window, cx);
17231        } else {
17232            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17233                editor
17234                    .update_in(cx, |editor, _, cx| {
17235                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17236                            editor.fold_buffer(buffer_id, cx);
17237                        }
17238                    })
17239                    .ok();
17240            });
17241        }
17242    }
17243
17244    pub fn fold_function_bodies(
17245        &mut self,
17246        _: &actions::FoldFunctionBodies,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        let snapshot = self.buffer.read(cx).snapshot(cx);
17251
17252        let ranges = snapshot
17253            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17254            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17255            .collect::<Vec<_>>();
17256
17257        let creases = ranges
17258            .into_iter()
17259            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17260            .collect();
17261
17262        self.fold_creases(creases, true, window, cx);
17263    }
17264
17265    pub fn fold_recursive(
17266        &mut self,
17267        _: &actions::FoldRecursive,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) {
17271        let mut to_fold = Vec::new();
17272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17273        let selections = self.selections.all_adjusted(cx);
17274
17275        for selection in selections {
17276            let range = selection.range().sorted();
17277            let buffer_start_row = range.start.row;
17278
17279            if range.start.row != range.end.row {
17280                let mut found = false;
17281                for row in range.start.row..=range.end.row {
17282                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17283                        found = true;
17284                        to_fold.push(crease);
17285                    }
17286                }
17287                if found {
17288                    continue;
17289                }
17290            }
17291
17292            for row in (0..=range.start.row).rev() {
17293                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17294                    if crease.range().end.row >= buffer_start_row {
17295                        to_fold.push(crease);
17296                    } else {
17297                        break;
17298                    }
17299                }
17300            }
17301        }
17302
17303        self.fold_creases(to_fold, true, window, cx);
17304    }
17305
17306    pub fn fold_at(
17307        &mut self,
17308        buffer_row: MultiBufferRow,
17309        window: &mut Window,
17310        cx: &mut Context<Self>,
17311    ) {
17312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17313
17314        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17315            let autoscroll = self
17316                .selections
17317                .all::<Point>(cx)
17318                .iter()
17319                .any(|selection| crease.range().overlaps(&selection.range()));
17320
17321            self.fold_creases(vec![crease], autoscroll, window, cx);
17322        }
17323    }
17324
17325    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17326        if self.is_singleton(cx) {
17327            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17328            let buffer = &display_map.buffer_snapshot;
17329            let selections = self.selections.all::<Point>(cx);
17330            let ranges = selections
17331                .iter()
17332                .map(|s| {
17333                    let range = s.display_range(&display_map).sorted();
17334                    let mut start = range.start.to_point(&display_map);
17335                    let mut end = range.end.to_point(&display_map);
17336                    start.column = 0;
17337                    end.column = buffer.line_len(MultiBufferRow(end.row));
17338                    start..end
17339                })
17340                .collect::<Vec<_>>();
17341
17342            self.unfold_ranges(&ranges, true, true, cx);
17343        } else {
17344            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17345            let buffer_ids = self
17346                .selections
17347                .disjoint_anchor_ranges()
17348                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17349                .collect::<HashSet<_>>();
17350            for buffer_id in buffer_ids {
17351                self.unfold_buffer(buffer_id, cx);
17352            }
17353        }
17354    }
17355
17356    pub fn unfold_recursive(
17357        &mut self,
17358        _: &UnfoldRecursive,
17359        _window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) {
17362        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17363        let selections = self.selections.all::<Point>(cx);
17364        let ranges = selections
17365            .iter()
17366            .map(|s| {
17367                let mut range = s.display_range(&display_map).sorted();
17368                *range.start.column_mut() = 0;
17369                *range.end.column_mut() = display_map.line_len(range.end.row());
17370                let start = range.start.to_point(&display_map);
17371                let end = range.end.to_point(&display_map);
17372                start..end
17373            })
17374            .collect::<Vec<_>>();
17375
17376        self.unfold_ranges(&ranges, true, true, cx);
17377    }
17378
17379    pub fn unfold_at(
17380        &mut self,
17381        buffer_row: MultiBufferRow,
17382        _window: &mut Window,
17383        cx: &mut Context<Self>,
17384    ) {
17385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17386
17387        let intersection_range = Point::new(buffer_row.0, 0)
17388            ..Point::new(
17389                buffer_row.0,
17390                display_map.buffer_snapshot.line_len(buffer_row),
17391            );
17392
17393        let autoscroll = self
17394            .selections
17395            .all::<Point>(cx)
17396            .iter()
17397            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17398
17399        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17400    }
17401
17402    pub fn unfold_all(
17403        &mut self,
17404        _: &actions::UnfoldAll,
17405        _window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        if self.buffer.read(cx).is_singleton() {
17409            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17410            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17411        } else {
17412            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17413                editor
17414                    .update(cx, |editor, cx| {
17415                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17416                            editor.unfold_buffer(buffer_id, cx);
17417                        }
17418                    })
17419                    .ok();
17420            });
17421        }
17422    }
17423
17424    pub fn fold_selected_ranges(
17425        &mut self,
17426        _: &FoldSelectedRanges,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        let selections = self.selections.all_adjusted(cx);
17431        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17432        let ranges = selections
17433            .into_iter()
17434            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17435            .collect::<Vec<_>>();
17436        self.fold_creases(ranges, true, window, cx);
17437    }
17438
17439    pub fn fold_ranges<T: ToOffset + Clone>(
17440        &mut self,
17441        ranges: Vec<Range<T>>,
17442        auto_scroll: bool,
17443        window: &mut Window,
17444        cx: &mut Context<Self>,
17445    ) {
17446        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17447        let ranges = ranges
17448            .into_iter()
17449            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17450            .collect::<Vec<_>>();
17451        self.fold_creases(ranges, auto_scroll, window, cx);
17452    }
17453
17454    pub fn fold_creases<T: ToOffset + Clone>(
17455        &mut self,
17456        creases: Vec<Crease<T>>,
17457        auto_scroll: bool,
17458        _window: &mut Window,
17459        cx: &mut Context<Self>,
17460    ) {
17461        if creases.is_empty() {
17462            return;
17463        }
17464
17465        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17466
17467        if auto_scroll {
17468            self.request_autoscroll(Autoscroll::fit(), cx);
17469        }
17470
17471        cx.notify();
17472
17473        self.scrollbar_marker_state.dirty = true;
17474        self.folds_did_change(cx);
17475    }
17476
17477    /// Removes any folds whose ranges intersect any of the given ranges.
17478    pub fn unfold_ranges<T: ToOffset + Clone>(
17479        &mut self,
17480        ranges: &[Range<T>],
17481        inclusive: bool,
17482        auto_scroll: bool,
17483        cx: &mut Context<Self>,
17484    ) {
17485        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17486            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17487        });
17488        self.folds_did_change(cx);
17489    }
17490
17491    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17492        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17493            return;
17494        }
17495        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17496        self.display_map.update(cx, |display_map, cx| {
17497            display_map.fold_buffers([buffer_id], cx)
17498        });
17499        cx.emit(EditorEvent::BufferFoldToggled {
17500            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17501            folded: true,
17502        });
17503        cx.notify();
17504    }
17505
17506    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17507        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17508            return;
17509        }
17510        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17511        self.display_map.update(cx, |display_map, cx| {
17512            display_map.unfold_buffers([buffer_id], cx);
17513        });
17514        cx.emit(EditorEvent::BufferFoldToggled {
17515            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17516            folded: false,
17517        });
17518        cx.notify();
17519    }
17520
17521    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17522        self.display_map.read(cx).is_buffer_folded(buffer)
17523    }
17524
17525    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17526        self.display_map.read(cx).folded_buffers()
17527    }
17528
17529    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17530        self.display_map.update(cx, |display_map, cx| {
17531            display_map.disable_header_for_buffer(buffer_id, cx);
17532        });
17533        cx.notify();
17534    }
17535
17536    /// Removes any folds with the given ranges.
17537    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17538        &mut self,
17539        ranges: &[Range<T>],
17540        type_id: TypeId,
17541        auto_scroll: bool,
17542        cx: &mut Context<Self>,
17543    ) {
17544        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17545            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17546        });
17547        self.folds_did_change(cx);
17548    }
17549
17550    fn remove_folds_with<T: ToOffset + Clone>(
17551        &mut self,
17552        ranges: &[Range<T>],
17553        auto_scroll: bool,
17554        cx: &mut Context<Self>,
17555        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17556    ) {
17557        if ranges.is_empty() {
17558            return;
17559        }
17560
17561        let mut buffers_affected = HashSet::default();
17562        let multi_buffer = self.buffer().read(cx);
17563        for range in ranges {
17564            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17565                buffers_affected.insert(buffer.read(cx).remote_id());
17566            };
17567        }
17568
17569        self.display_map.update(cx, update);
17570
17571        if auto_scroll {
17572            self.request_autoscroll(Autoscroll::fit(), cx);
17573        }
17574
17575        cx.notify();
17576        self.scrollbar_marker_state.dirty = true;
17577        self.active_indent_guides_state.dirty = true;
17578    }
17579
17580    pub fn update_renderer_widths(
17581        &mut self,
17582        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17583        cx: &mut Context<Self>,
17584    ) -> bool {
17585        self.display_map
17586            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17587    }
17588
17589    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17590        self.display_map.read(cx).fold_placeholder.clone()
17591    }
17592
17593    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17594        self.buffer.update(cx, |buffer, cx| {
17595            buffer.set_all_diff_hunks_expanded(cx);
17596        });
17597    }
17598
17599    pub fn expand_all_diff_hunks(
17600        &mut self,
17601        _: &ExpandAllDiffHunks,
17602        _window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        self.buffer.update(cx, |buffer, cx| {
17606            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17607        });
17608    }
17609
17610    pub fn toggle_selected_diff_hunks(
17611        &mut self,
17612        _: &ToggleSelectedDiffHunks,
17613        _window: &mut Window,
17614        cx: &mut Context<Self>,
17615    ) {
17616        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17617        self.toggle_diff_hunks_in_ranges(ranges, cx);
17618    }
17619
17620    pub fn diff_hunks_in_ranges<'a>(
17621        &'a self,
17622        ranges: &'a [Range<Anchor>],
17623        buffer: &'a MultiBufferSnapshot,
17624    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17625        ranges.iter().flat_map(move |range| {
17626            let end_excerpt_id = range.end.excerpt_id;
17627            let range = range.to_point(buffer);
17628            let mut peek_end = range.end;
17629            if range.end.row < buffer.max_row().0 {
17630                peek_end = Point::new(range.end.row + 1, 0);
17631            }
17632            buffer
17633                .diff_hunks_in_range(range.start..peek_end)
17634                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17635        })
17636    }
17637
17638    pub fn has_stageable_diff_hunks_in_ranges(
17639        &self,
17640        ranges: &[Range<Anchor>],
17641        snapshot: &MultiBufferSnapshot,
17642    ) -> bool {
17643        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17644        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17645    }
17646
17647    pub fn toggle_staged_selected_diff_hunks(
17648        &mut self,
17649        _: &::git::ToggleStaged,
17650        _: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) {
17653        let snapshot = self.buffer.read(cx).snapshot(cx);
17654        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17655        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17656        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17657    }
17658
17659    pub fn set_render_diff_hunk_controls(
17660        &mut self,
17661        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17662        cx: &mut Context<Self>,
17663    ) {
17664        self.render_diff_hunk_controls = render_diff_hunk_controls;
17665        cx.notify();
17666    }
17667
17668    pub fn stage_and_next(
17669        &mut self,
17670        _: &::git::StageAndNext,
17671        window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) {
17674        self.do_stage_or_unstage_and_next(true, window, cx);
17675    }
17676
17677    pub fn unstage_and_next(
17678        &mut self,
17679        _: &::git::UnstageAndNext,
17680        window: &mut Window,
17681        cx: &mut Context<Self>,
17682    ) {
17683        self.do_stage_or_unstage_and_next(false, window, cx);
17684    }
17685
17686    pub fn stage_or_unstage_diff_hunks(
17687        &mut self,
17688        stage: bool,
17689        ranges: Vec<Range<Anchor>>,
17690        cx: &mut Context<Self>,
17691    ) {
17692        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17693        cx.spawn(async move |this, cx| {
17694            task.await?;
17695            this.update(cx, |this, cx| {
17696                let snapshot = this.buffer.read(cx).snapshot(cx);
17697                let chunk_by = this
17698                    .diff_hunks_in_ranges(&ranges, &snapshot)
17699                    .chunk_by(|hunk| hunk.buffer_id);
17700                for (buffer_id, hunks) in &chunk_by {
17701                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17702                }
17703            })
17704        })
17705        .detach_and_log_err(cx);
17706    }
17707
17708    fn save_buffers_for_ranges_if_needed(
17709        &mut self,
17710        ranges: &[Range<Anchor>],
17711        cx: &mut Context<Editor>,
17712    ) -> Task<Result<()>> {
17713        let multibuffer = self.buffer.read(cx);
17714        let snapshot = multibuffer.read(cx);
17715        let buffer_ids: HashSet<_> = ranges
17716            .iter()
17717            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17718            .collect();
17719        drop(snapshot);
17720
17721        let mut buffers = HashSet::default();
17722        for buffer_id in buffer_ids {
17723            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17724                let buffer = buffer_entity.read(cx);
17725                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17726                {
17727                    buffers.insert(buffer_entity);
17728                }
17729            }
17730        }
17731
17732        if let Some(project) = &self.project {
17733            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17734        } else {
17735            Task::ready(Ok(()))
17736        }
17737    }
17738
17739    fn do_stage_or_unstage_and_next(
17740        &mut self,
17741        stage: bool,
17742        window: &mut Window,
17743        cx: &mut Context<Self>,
17744    ) {
17745        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17746
17747        if ranges.iter().any(|range| range.start != range.end) {
17748            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17749            return;
17750        }
17751
17752        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17753        let snapshot = self.snapshot(window, cx);
17754        let position = self.selections.newest::<Point>(cx).head();
17755        let mut row = snapshot
17756            .buffer_snapshot
17757            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17758            .find(|hunk| hunk.row_range.start.0 > position.row)
17759            .map(|hunk| hunk.row_range.start);
17760
17761        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17762        // Outside of the project diff editor, wrap around to the beginning.
17763        if !all_diff_hunks_expanded {
17764            row = row.or_else(|| {
17765                snapshot
17766                    .buffer_snapshot
17767                    .diff_hunks_in_range(Point::zero()..position)
17768                    .find(|hunk| hunk.row_range.end.0 < position.row)
17769                    .map(|hunk| hunk.row_range.start)
17770            });
17771        }
17772
17773        if let Some(row) = row {
17774            let destination = Point::new(row.0, 0);
17775            let autoscroll = Autoscroll::center();
17776
17777            self.unfold_ranges(&[destination..destination], false, false, cx);
17778            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17779                s.select_ranges([destination..destination]);
17780            });
17781        }
17782    }
17783
17784    fn do_stage_or_unstage(
17785        &self,
17786        stage: bool,
17787        buffer_id: BufferId,
17788        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17789        cx: &mut App,
17790    ) -> Option<()> {
17791        let project = self.project.as_ref()?;
17792        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17793        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17794        let buffer_snapshot = buffer.read(cx).snapshot();
17795        let file_exists = buffer_snapshot
17796            .file()
17797            .is_some_and(|file| file.disk_state().exists());
17798        diff.update(cx, |diff, cx| {
17799            diff.stage_or_unstage_hunks(
17800                stage,
17801                &hunks
17802                    .map(|hunk| buffer_diff::DiffHunk {
17803                        buffer_range: hunk.buffer_range,
17804                        diff_base_byte_range: hunk.diff_base_byte_range,
17805                        secondary_status: hunk.secondary_status,
17806                        range: Point::zero()..Point::zero(), // unused
17807                    })
17808                    .collect::<Vec<_>>(),
17809                &buffer_snapshot,
17810                file_exists,
17811                cx,
17812            )
17813        });
17814        None
17815    }
17816
17817    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17818        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17819        self.buffer
17820            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17821    }
17822
17823    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17824        self.buffer.update(cx, |buffer, cx| {
17825            let ranges = vec![Anchor::min()..Anchor::max()];
17826            if !buffer.all_diff_hunks_expanded()
17827                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17828            {
17829                buffer.collapse_diff_hunks(ranges, cx);
17830                true
17831            } else {
17832                false
17833            }
17834        })
17835    }
17836
17837    fn toggle_diff_hunks_in_ranges(
17838        &mut self,
17839        ranges: Vec<Range<Anchor>>,
17840        cx: &mut Context<Editor>,
17841    ) {
17842        self.buffer.update(cx, |buffer, cx| {
17843            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17844            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17845        })
17846    }
17847
17848    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17849        self.buffer.update(cx, |buffer, cx| {
17850            let snapshot = buffer.snapshot(cx);
17851            let excerpt_id = range.end.excerpt_id;
17852            let point_range = range.to_point(&snapshot);
17853            let expand = !buffer.single_hunk_is_expanded(range, cx);
17854            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17855        })
17856    }
17857
17858    pub(crate) fn apply_all_diff_hunks(
17859        &mut self,
17860        _: &ApplyAllDiffHunks,
17861        window: &mut Window,
17862        cx: &mut Context<Self>,
17863    ) {
17864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17865
17866        let buffers = self.buffer.read(cx).all_buffers();
17867        for branch_buffer in buffers {
17868            branch_buffer.update(cx, |branch_buffer, cx| {
17869                branch_buffer.merge_into_base(Vec::new(), cx);
17870            });
17871        }
17872
17873        if let Some(project) = self.project.clone() {
17874            self.save(
17875                SaveOptions {
17876                    format: true,
17877                    autosave: false,
17878                },
17879                project,
17880                window,
17881                cx,
17882            )
17883            .detach_and_log_err(cx);
17884        }
17885    }
17886
17887    pub(crate) fn apply_selected_diff_hunks(
17888        &mut self,
17889        _: &ApplyDiffHunk,
17890        window: &mut Window,
17891        cx: &mut Context<Self>,
17892    ) {
17893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17894        let snapshot = self.snapshot(window, cx);
17895        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17896        let mut ranges_by_buffer = HashMap::default();
17897        self.transact(window, cx, |editor, _window, cx| {
17898            for hunk in hunks {
17899                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17900                    ranges_by_buffer
17901                        .entry(buffer.clone())
17902                        .or_insert_with(Vec::new)
17903                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17904                }
17905            }
17906
17907            for (buffer, ranges) in ranges_by_buffer {
17908                buffer.update(cx, |buffer, cx| {
17909                    buffer.merge_into_base(ranges, cx);
17910                });
17911            }
17912        });
17913
17914        if let Some(project) = self.project.clone() {
17915            self.save(
17916                SaveOptions {
17917                    format: true,
17918                    autosave: false,
17919                },
17920                project,
17921                window,
17922                cx,
17923            )
17924            .detach_and_log_err(cx);
17925        }
17926    }
17927
17928    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17929        if hovered != self.gutter_hovered {
17930            self.gutter_hovered = hovered;
17931            cx.notify();
17932        }
17933    }
17934
17935    pub fn insert_blocks(
17936        &mut self,
17937        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17938        autoscroll: Option<Autoscroll>,
17939        cx: &mut Context<Self>,
17940    ) -> Vec<CustomBlockId> {
17941        let blocks = self
17942            .display_map
17943            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17944        if let Some(autoscroll) = autoscroll {
17945            self.request_autoscroll(autoscroll, cx);
17946        }
17947        cx.notify();
17948        blocks
17949    }
17950
17951    pub fn resize_blocks(
17952        &mut self,
17953        heights: HashMap<CustomBlockId, u32>,
17954        autoscroll: Option<Autoscroll>,
17955        cx: &mut Context<Self>,
17956    ) {
17957        self.display_map
17958            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17959        if let Some(autoscroll) = autoscroll {
17960            self.request_autoscroll(autoscroll, cx);
17961        }
17962        cx.notify();
17963    }
17964
17965    pub fn replace_blocks(
17966        &mut self,
17967        renderers: HashMap<CustomBlockId, RenderBlock>,
17968        autoscroll: Option<Autoscroll>,
17969        cx: &mut Context<Self>,
17970    ) {
17971        self.display_map
17972            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17973        if let Some(autoscroll) = autoscroll {
17974            self.request_autoscroll(autoscroll, cx);
17975        }
17976        cx.notify();
17977    }
17978
17979    pub fn remove_blocks(
17980        &mut self,
17981        block_ids: HashSet<CustomBlockId>,
17982        autoscroll: Option<Autoscroll>,
17983        cx: &mut Context<Self>,
17984    ) {
17985        self.display_map.update(cx, |display_map, cx| {
17986            display_map.remove_blocks(block_ids, cx)
17987        });
17988        if let Some(autoscroll) = autoscroll {
17989            self.request_autoscroll(autoscroll, cx);
17990        }
17991        cx.notify();
17992    }
17993
17994    pub fn row_for_block(
17995        &self,
17996        block_id: CustomBlockId,
17997        cx: &mut Context<Self>,
17998    ) -> Option<DisplayRow> {
17999        self.display_map
18000            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18001    }
18002
18003    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18004        self.focused_block = Some(focused_block);
18005    }
18006
18007    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18008        self.focused_block.take()
18009    }
18010
18011    pub fn insert_creases(
18012        &mut self,
18013        creases: impl IntoIterator<Item = Crease<Anchor>>,
18014        cx: &mut Context<Self>,
18015    ) -> Vec<CreaseId> {
18016        self.display_map
18017            .update(cx, |map, cx| map.insert_creases(creases, cx))
18018    }
18019
18020    pub fn remove_creases(
18021        &mut self,
18022        ids: impl IntoIterator<Item = CreaseId>,
18023        cx: &mut Context<Self>,
18024    ) -> Vec<(CreaseId, Range<Anchor>)> {
18025        self.display_map
18026            .update(cx, |map, cx| map.remove_creases(ids, cx))
18027    }
18028
18029    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18030        self.display_map
18031            .update(cx, |map, cx| map.snapshot(cx))
18032            .longest_row()
18033    }
18034
18035    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18036        self.display_map
18037            .update(cx, |map, cx| map.snapshot(cx))
18038            .max_point()
18039    }
18040
18041    pub fn text(&self, cx: &App) -> String {
18042        self.buffer.read(cx).read(cx).text()
18043    }
18044
18045    pub fn is_empty(&self, cx: &App) -> bool {
18046        self.buffer.read(cx).read(cx).is_empty()
18047    }
18048
18049    pub fn text_option(&self, cx: &App) -> Option<String> {
18050        let text = self.text(cx);
18051        let text = text.trim();
18052
18053        if text.is_empty() {
18054            return None;
18055        }
18056
18057        Some(text.to_string())
18058    }
18059
18060    pub fn set_text(
18061        &mut self,
18062        text: impl Into<Arc<str>>,
18063        window: &mut Window,
18064        cx: &mut Context<Self>,
18065    ) {
18066        self.transact(window, cx, |this, _, cx| {
18067            this.buffer
18068                .read(cx)
18069                .as_singleton()
18070                .expect("you can only call set_text on editors for singleton buffers")
18071                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18072        });
18073    }
18074
18075    pub fn display_text(&self, cx: &mut App) -> String {
18076        self.display_map
18077            .update(cx, |map, cx| map.snapshot(cx))
18078            .text()
18079    }
18080
18081    fn create_minimap(
18082        &self,
18083        minimap_settings: MinimapSettings,
18084        window: &mut Window,
18085        cx: &mut Context<Self>,
18086    ) -> Option<Entity<Self>> {
18087        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18088            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18089    }
18090
18091    fn initialize_new_minimap(
18092        &self,
18093        minimap_settings: MinimapSettings,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) -> Entity<Self> {
18097        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18098
18099        let mut minimap = Editor::new_internal(
18100            EditorMode::Minimap {
18101                parent: cx.weak_entity(),
18102            },
18103            self.buffer.clone(),
18104            None,
18105            Some(self.display_map.clone()),
18106            window,
18107            cx,
18108        );
18109        minimap.scroll_manager.clone_state(&self.scroll_manager);
18110        minimap.set_text_style_refinement(TextStyleRefinement {
18111            font_size: Some(MINIMAP_FONT_SIZE),
18112            font_weight: Some(MINIMAP_FONT_WEIGHT),
18113            ..Default::default()
18114        });
18115        minimap.update_minimap_configuration(minimap_settings, cx);
18116        cx.new(|_| minimap)
18117    }
18118
18119    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18120        let current_line_highlight = minimap_settings
18121            .current_line_highlight
18122            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18123        self.set_current_line_highlight(Some(current_line_highlight));
18124    }
18125
18126    pub fn minimap(&self) -> Option<&Entity<Self>> {
18127        self.minimap
18128            .as_ref()
18129            .filter(|_| self.minimap_visibility.visible())
18130    }
18131
18132    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18133        let mut wrap_guides = smallvec![];
18134
18135        if self.show_wrap_guides == Some(false) {
18136            return wrap_guides;
18137        }
18138
18139        let settings = self.buffer.read(cx).language_settings(cx);
18140        if settings.show_wrap_guides {
18141            match self.soft_wrap_mode(cx) {
18142                SoftWrap::Column(soft_wrap) => {
18143                    wrap_guides.push((soft_wrap as usize, true));
18144                }
18145                SoftWrap::Bounded(soft_wrap) => {
18146                    wrap_guides.push((soft_wrap as usize, true));
18147                }
18148                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18149            }
18150            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18151        }
18152
18153        wrap_guides
18154    }
18155
18156    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18157        let settings = self.buffer.read(cx).language_settings(cx);
18158        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18159        match mode {
18160            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18161                SoftWrap::None
18162            }
18163            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18164            language_settings::SoftWrap::PreferredLineLength => {
18165                SoftWrap::Column(settings.preferred_line_length)
18166            }
18167            language_settings::SoftWrap::Bounded => {
18168                SoftWrap::Bounded(settings.preferred_line_length)
18169            }
18170        }
18171    }
18172
18173    pub fn set_soft_wrap_mode(
18174        &mut self,
18175        mode: language_settings::SoftWrap,
18176
18177        cx: &mut Context<Self>,
18178    ) {
18179        self.soft_wrap_mode_override = Some(mode);
18180        cx.notify();
18181    }
18182
18183    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18184        self.hard_wrap = hard_wrap;
18185        cx.notify();
18186    }
18187
18188    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18189        self.text_style_refinement = Some(style);
18190    }
18191
18192    /// called by the Element so we know what style we were most recently rendered with.
18193    pub(crate) fn set_style(
18194        &mut self,
18195        style: EditorStyle,
18196        window: &mut Window,
18197        cx: &mut Context<Self>,
18198    ) {
18199        // We intentionally do not inform the display map about the minimap style
18200        // so that wrapping is not recalculated and stays consistent for the editor
18201        // and its linked minimap.
18202        if !self.mode.is_minimap() {
18203            let rem_size = window.rem_size();
18204            self.display_map.update(cx, |map, cx| {
18205                map.set_font(
18206                    style.text.font(),
18207                    style.text.font_size.to_pixels(rem_size),
18208                    cx,
18209                )
18210            });
18211        }
18212        self.style = Some(style);
18213    }
18214
18215    pub fn style(&self) -> Option<&EditorStyle> {
18216        self.style.as_ref()
18217    }
18218
18219    // Called by the element. This method is not designed to be called outside of the editor
18220    // element's layout code because it does not notify when rewrapping is computed synchronously.
18221    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18222        self.display_map
18223            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18224    }
18225
18226    pub fn set_soft_wrap(&mut self) {
18227        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18228    }
18229
18230    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18231        if self.soft_wrap_mode_override.is_some() {
18232            self.soft_wrap_mode_override.take();
18233        } else {
18234            let soft_wrap = match self.soft_wrap_mode(cx) {
18235                SoftWrap::GitDiff => return,
18236                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18237                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18238                    language_settings::SoftWrap::None
18239                }
18240            };
18241            self.soft_wrap_mode_override = Some(soft_wrap);
18242        }
18243        cx.notify();
18244    }
18245
18246    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18247        let Some(workspace) = self.workspace() else {
18248            return;
18249        };
18250        let fs = workspace.read(cx).app_state().fs.clone();
18251        let current_show = TabBarSettings::get_global(cx).show;
18252        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18253            setting.show = Some(!current_show);
18254        });
18255    }
18256
18257    pub fn toggle_indent_guides(
18258        &mut self,
18259        _: &ToggleIndentGuides,
18260        _: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) {
18263        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18264            self.buffer
18265                .read(cx)
18266                .language_settings(cx)
18267                .indent_guides
18268                .enabled
18269        });
18270        self.show_indent_guides = Some(!currently_enabled);
18271        cx.notify();
18272    }
18273
18274    fn should_show_indent_guides(&self) -> Option<bool> {
18275        self.show_indent_guides
18276    }
18277
18278    pub fn toggle_line_numbers(
18279        &mut self,
18280        _: &ToggleLineNumbers,
18281        _: &mut Window,
18282        cx: &mut Context<Self>,
18283    ) {
18284        let mut editor_settings = EditorSettings::get_global(cx).clone();
18285        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18286        EditorSettings::override_global(editor_settings, cx);
18287    }
18288
18289    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18290        if let Some(show_line_numbers) = self.show_line_numbers {
18291            return show_line_numbers;
18292        }
18293        EditorSettings::get_global(cx).gutter.line_numbers
18294    }
18295
18296    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18297        self.use_relative_line_numbers
18298            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18299    }
18300
18301    pub fn toggle_relative_line_numbers(
18302        &mut self,
18303        _: &ToggleRelativeLineNumbers,
18304        _: &mut Window,
18305        cx: &mut Context<Self>,
18306    ) {
18307        let is_relative = self.should_use_relative_line_numbers(cx);
18308        self.set_relative_line_number(Some(!is_relative), cx)
18309    }
18310
18311    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18312        self.use_relative_line_numbers = is_relative;
18313        cx.notify();
18314    }
18315
18316    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18317        self.show_gutter = show_gutter;
18318        cx.notify();
18319    }
18320
18321    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18322        self.show_scrollbars = ScrollbarAxes {
18323            horizontal: show,
18324            vertical: show,
18325        };
18326        cx.notify();
18327    }
18328
18329    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18330        self.show_scrollbars.vertical = show;
18331        cx.notify();
18332    }
18333
18334    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18335        self.show_scrollbars.horizontal = show;
18336        cx.notify();
18337    }
18338
18339    pub fn set_minimap_visibility(
18340        &mut self,
18341        minimap_visibility: MinimapVisibility,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        if self.minimap_visibility != minimap_visibility {
18346            if minimap_visibility.visible() && self.minimap.is_none() {
18347                let minimap_settings = EditorSettings::get_global(cx).minimap;
18348                self.minimap =
18349                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18350            }
18351            self.minimap_visibility = minimap_visibility;
18352            cx.notify();
18353        }
18354    }
18355
18356    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18357        self.set_show_scrollbars(false, cx);
18358        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18359    }
18360
18361    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18362        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18363    }
18364
18365    /// Normally the text in full mode and auto height editors is padded on the
18366    /// left side by roughly half a character width for improved hit testing.
18367    ///
18368    /// Use this method to disable this for cases where this is not wanted (e.g.
18369    /// if you want to align the editor text with some other text above or below)
18370    /// or if you want to add this padding to single-line editors.
18371    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18372        self.offset_content = offset_content;
18373        cx.notify();
18374    }
18375
18376    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18377        self.show_line_numbers = Some(show_line_numbers);
18378        cx.notify();
18379    }
18380
18381    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18382        self.disable_expand_excerpt_buttons = true;
18383        cx.notify();
18384    }
18385
18386    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18387        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18388        cx.notify();
18389    }
18390
18391    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18392        self.show_code_actions = Some(show_code_actions);
18393        cx.notify();
18394    }
18395
18396    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18397        self.show_runnables = Some(show_runnables);
18398        cx.notify();
18399    }
18400
18401    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18402        self.show_breakpoints = Some(show_breakpoints);
18403        cx.notify();
18404    }
18405
18406    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18407        if self.display_map.read(cx).masked != masked {
18408            self.display_map.update(cx, |map, _| map.masked = masked);
18409        }
18410        cx.notify()
18411    }
18412
18413    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18414        self.show_wrap_guides = Some(show_wrap_guides);
18415        cx.notify();
18416    }
18417
18418    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18419        self.show_indent_guides = Some(show_indent_guides);
18420        cx.notify();
18421    }
18422
18423    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18424        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18425            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18426                if let Some(dir) = file.abs_path(cx).parent() {
18427                    return Some(dir.to_owned());
18428                }
18429            }
18430
18431            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18432                return Some(project_path.path.to_path_buf());
18433            }
18434        }
18435
18436        None
18437    }
18438
18439    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18440        self.active_excerpt(cx)?
18441            .1
18442            .read(cx)
18443            .file()
18444            .and_then(|f| f.as_local())
18445    }
18446
18447    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18448        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18449            let buffer = buffer.read(cx);
18450            if let Some(project_path) = buffer.project_path(cx) {
18451                let project = self.project.as_ref()?.read(cx);
18452                project.absolute_path(&project_path, cx)
18453            } else {
18454                buffer
18455                    .file()
18456                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18457            }
18458        })
18459    }
18460
18461    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18462        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18463            let project_path = buffer.read(cx).project_path(cx)?;
18464            let project = self.project.as_ref()?.read(cx);
18465            let entry = project.entry_for_path(&project_path, cx)?;
18466            let path = entry.path.to_path_buf();
18467            Some(path)
18468        })
18469    }
18470
18471    pub fn reveal_in_finder(
18472        &mut self,
18473        _: &RevealInFileManager,
18474        _window: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        if let Some(target) = self.target_file(cx) {
18478            cx.reveal_path(&target.abs_path(cx));
18479        }
18480    }
18481
18482    pub fn copy_path(
18483        &mut self,
18484        _: &zed_actions::workspace::CopyPath,
18485        _window: &mut Window,
18486        cx: &mut Context<Self>,
18487    ) {
18488        if let Some(path) = self.target_file_abs_path(cx) {
18489            if let Some(path) = path.to_str() {
18490                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18491            }
18492        }
18493    }
18494
18495    pub fn copy_relative_path(
18496        &mut self,
18497        _: &zed_actions::workspace::CopyRelativePath,
18498        _window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        if let Some(path) = self.target_file_path(cx) {
18502            if let Some(path) = path.to_str() {
18503                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18504            }
18505        }
18506    }
18507
18508    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18509        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18510            buffer.read(cx).project_path(cx)
18511        } else {
18512            None
18513        }
18514    }
18515
18516    // Returns true if the editor handled a go-to-line request
18517    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18518        maybe!({
18519            let breakpoint_store = self.breakpoint_store.as_ref()?;
18520
18521            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18522            else {
18523                self.clear_row_highlights::<ActiveDebugLine>();
18524                return None;
18525            };
18526
18527            let position = active_stack_frame.position;
18528            let buffer_id = position.buffer_id?;
18529            let snapshot = self
18530                .project
18531                .as_ref()?
18532                .read(cx)
18533                .buffer_for_id(buffer_id, cx)?
18534                .read(cx)
18535                .snapshot();
18536
18537            let mut handled = false;
18538            for (id, ExcerptRange { context, .. }) in
18539                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18540            {
18541                if context.start.cmp(&position, &snapshot).is_ge()
18542                    || context.end.cmp(&position, &snapshot).is_lt()
18543                {
18544                    continue;
18545                }
18546                let snapshot = self.buffer.read(cx).snapshot(cx);
18547                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18548
18549                handled = true;
18550                self.clear_row_highlights::<ActiveDebugLine>();
18551
18552                self.go_to_line::<ActiveDebugLine>(
18553                    multibuffer_anchor,
18554                    Some(cx.theme().colors().editor_debugger_active_line_background),
18555                    window,
18556                    cx,
18557                );
18558
18559                cx.notify();
18560            }
18561
18562            handled.then_some(())
18563        })
18564        .is_some()
18565    }
18566
18567    pub fn copy_file_name_without_extension(
18568        &mut self,
18569        _: &CopyFileNameWithoutExtension,
18570        _: &mut Window,
18571        cx: &mut Context<Self>,
18572    ) {
18573        if let Some(file) = self.target_file(cx) {
18574            if let Some(file_stem) = file.path().file_stem() {
18575                if let Some(name) = file_stem.to_str() {
18576                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18577                }
18578            }
18579        }
18580    }
18581
18582    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18583        if let Some(file) = self.target_file(cx) {
18584            if let Some(file_name) = file.path().file_name() {
18585                if let Some(name) = file_name.to_str() {
18586                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18587                }
18588            }
18589        }
18590    }
18591
18592    pub fn toggle_git_blame(
18593        &mut self,
18594        _: &::git::Blame,
18595        window: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) {
18598        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18599
18600        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18601            self.start_git_blame(true, window, cx);
18602        }
18603
18604        cx.notify();
18605    }
18606
18607    pub fn toggle_git_blame_inline(
18608        &mut self,
18609        _: &ToggleGitBlameInline,
18610        window: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        self.toggle_git_blame_inline_internal(true, window, cx);
18614        cx.notify();
18615    }
18616
18617    pub fn open_git_blame_commit(
18618        &mut self,
18619        _: &OpenGitBlameCommit,
18620        window: &mut Window,
18621        cx: &mut Context<Self>,
18622    ) {
18623        self.open_git_blame_commit_internal(window, cx);
18624    }
18625
18626    fn open_git_blame_commit_internal(
18627        &mut self,
18628        window: &mut Window,
18629        cx: &mut Context<Self>,
18630    ) -> Option<()> {
18631        let blame = self.blame.as_ref()?;
18632        let snapshot = self.snapshot(window, cx);
18633        let cursor = self.selections.newest::<Point>(cx).head();
18634        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18635        let blame_entry = blame
18636            .update(cx, |blame, cx| {
18637                blame
18638                    .blame_for_rows(
18639                        &[RowInfo {
18640                            buffer_id: Some(buffer.remote_id()),
18641                            buffer_row: Some(point.row),
18642                            ..Default::default()
18643                        }],
18644                        cx,
18645                    )
18646                    .next()
18647            })
18648            .flatten()?;
18649        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18650        let repo = blame.read(cx).repository(cx)?;
18651        let workspace = self.workspace()?.downgrade();
18652        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18653        None
18654    }
18655
18656    pub fn git_blame_inline_enabled(&self) -> bool {
18657        self.git_blame_inline_enabled
18658    }
18659
18660    pub fn toggle_selection_menu(
18661        &mut self,
18662        _: &ToggleSelectionMenu,
18663        _: &mut Window,
18664        cx: &mut Context<Self>,
18665    ) {
18666        self.show_selection_menu = self
18667            .show_selection_menu
18668            .map(|show_selections_menu| !show_selections_menu)
18669            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18670
18671        cx.notify();
18672    }
18673
18674    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18675        self.show_selection_menu
18676            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18677    }
18678
18679    fn start_git_blame(
18680        &mut self,
18681        user_triggered: bool,
18682        window: &mut Window,
18683        cx: &mut Context<Self>,
18684    ) {
18685        if let Some(project) = self.project.as_ref() {
18686            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18687                return;
18688            };
18689
18690            if buffer.read(cx).file().is_none() {
18691                return;
18692            }
18693
18694            let focused = self.focus_handle(cx).contains_focused(window, cx);
18695
18696            let project = project.clone();
18697            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18698            self.blame_subscription =
18699                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18700            self.blame = Some(blame);
18701        }
18702    }
18703
18704    fn toggle_git_blame_inline_internal(
18705        &mut self,
18706        user_triggered: bool,
18707        window: &mut Window,
18708        cx: &mut Context<Self>,
18709    ) {
18710        if self.git_blame_inline_enabled {
18711            self.git_blame_inline_enabled = false;
18712            self.show_git_blame_inline = false;
18713            self.show_git_blame_inline_delay_task.take();
18714        } else {
18715            self.git_blame_inline_enabled = true;
18716            self.start_git_blame_inline(user_triggered, window, cx);
18717        }
18718
18719        cx.notify();
18720    }
18721
18722    fn start_git_blame_inline(
18723        &mut self,
18724        user_triggered: bool,
18725        window: &mut Window,
18726        cx: &mut Context<Self>,
18727    ) {
18728        self.start_git_blame(user_triggered, window, cx);
18729
18730        if ProjectSettings::get_global(cx)
18731            .git
18732            .inline_blame_delay()
18733            .is_some()
18734        {
18735            self.start_inline_blame_timer(window, cx);
18736        } else {
18737            self.show_git_blame_inline = true
18738        }
18739    }
18740
18741    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18742        self.blame.as_ref()
18743    }
18744
18745    pub fn show_git_blame_gutter(&self) -> bool {
18746        self.show_git_blame_gutter
18747    }
18748
18749    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18750        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18751    }
18752
18753    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18754        self.show_git_blame_inline
18755            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18756            && !self.newest_selection_head_on_empty_line(cx)
18757            && self.has_blame_entries(cx)
18758    }
18759
18760    fn has_blame_entries(&self, cx: &App) -> bool {
18761        self.blame()
18762            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18763    }
18764
18765    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18766        let cursor_anchor = self.selections.newest_anchor().head();
18767
18768        let snapshot = self.buffer.read(cx).snapshot(cx);
18769        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18770
18771        snapshot.line_len(buffer_row) == 0
18772    }
18773
18774    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18775        let buffer_and_selection = maybe!({
18776            let selection = self.selections.newest::<Point>(cx);
18777            let selection_range = selection.range();
18778
18779            let multi_buffer = self.buffer().read(cx);
18780            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18781            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18782
18783            let (buffer, range, _) = if selection.reversed {
18784                buffer_ranges.first()
18785            } else {
18786                buffer_ranges.last()
18787            }?;
18788
18789            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18790                ..text::ToPoint::to_point(&range.end, &buffer).row;
18791            Some((
18792                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18793                selection,
18794            ))
18795        });
18796
18797        let Some((buffer, selection)) = buffer_and_selection else {
18798            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18799        };
18800
18801        let Some(project) = self.project.as_ref() else {
18802            return Task::ready(Err(anyhow!("editor does not have project")));
18803        };
18804
18805        project.update(cx, |project, cx| {
18806            project.get_permalink_to_line(&buffer, selection, cx)
18807        })
18808    }
18809
18810    pub fn copy_permalink_to_line(
18811        &mut self,
18812        _: &CopyPermalinkToLine,
18813        window: &mut Window,
18814        cx: &mut Context<Self>,
18815    ) {
18816        let permalink_task = self.get_permalink_to_line(cx);
18817        let workspace = self.workspace();
18818
18819        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18820            Ok(permalink) => {
18821                cx.update(|_, cx| {
18822                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18823                })
18824                .ok();
18825            }
18826            Err(err) => {
18827                let message = format!("Failed to copy permalink: {err}");
18828
18829                anyhow::Result::<()>::Err(err).log_err();
18830
18831                if let Some(workspace) = workspace {
18832                    workspace
18833                        .update_in(cx, |workspace, _, cx| {
18834                            struct CopyPermalinkToLine;
18835
18836                            workspace.show_toast(
18837                                Toast::new(
18838                                    NotificationId::unique::<CopyPermalinkToLine>(),
18839                                    message,
18840                                ),
18841                                cx,
18842                            )
18843                        })
18844                        .ok();
18845                }
18846            }
18847        })
18848        .detach();
18849    }
18850
18851    pub fn copy_file_location(
18852        &mut self,
18853        _: &CopyFileLocation,
18854        _: &mut Window,
18855        cx: &mut Context<Self>,
18856    ) {
18857        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18858        if let Some(file) = self.target_file(cx) {
18859            if let Some(path) = file.path().to_str() {
18860                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18861            }
18862        }
18863    }
18864
18865    pub fn open_permalink_to_line(
18866        &mut self,
18867        _: &OpenPermalinkToLine,
18868        window: &mut Window,
18869        cx: &mut Context<Self>,
18870    ) {
18871        let permalink_task = self.get_permalink_to_line(cx);
18872        let workspace = self.workspace();
18873
18874        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18875            Ok(permalink) => {
18876                cx.update(|_, cx| {
18877                    cx.open_url(permalink.as_ref());
18878                })
18879                .ok();
18880            }
18881            Err(err) => {
18882                let message = format!("Failed to open permalink: {err}");
18883
18884                anyhow::Result::<()>::Err(err).log_err();
18885
18886                if let Some(workspace) = workspace {
18887                    workspace
18888                        .update(cx, |workspace, cx| {
18889                            struct OpenPermalinkToLine;
18890
18891                            workspace.show_toast(
18892                                Toast::new(
18893                                    NotificationId::unique::<OpenPermalinkToLine>(),
18894                                    message,
18895                                ),
18896                                cx,
18897                            )
18898                        })
18899                        .ok();
18900                }
18901            }
18902        })
18903        .detach();
18904    }
18905
18906    pub fn insert_uuid_v4(
18907        &mut self,
18908        _: &InsertUuidV4,
18909        window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) {
18912        self.insert_uuid(UuidVersion::V4, window, cx);
18913    }
18914
18915    pub fn insert_uuid_v7(
18916        &mut self,
18917        _: &InsertUuidV7,
18918        window: &mut Window,
18919        cx: &mut Context<Self>,
18920    ) {
18921        self.insert_uuid(UuidVersion::V7, window, cx);
18922    }
18923
18924    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18926        self.transact(window, cx, |this, window, cx| {
18927            let edits = this
18928                .selections
18929                .all::<Point>(cx)
18930                .into_iter()
18931                .map(|selection| {
18932                    let uuid = match version {
18933                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18934                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18935                    };
18936
18937                    (selection.range(), uuid.to_string())
18938                });
18939            this.edit(edits, cx);
18940            this.refresh_inline_completion(true, false, window, cx);
18941        });
18942    }
18943
18944    pub fn open_selections_in_multibuffer(
18945        &mut self,
18946        _: &OpenSelectionsInMultibuffer,
18947        window: &mut Window,
18948        cx: &mut Context<Self>,
18949    ) {
18950        let multibuffer = self.buffer.read(cx);
18951
18952        let Some(buffer) = multibuffer.as_singleton() else {
18953            return;
18954        };
18955
18956        let Some(workspace) = self.workspace() else {
18957            return;
18958        };
18959
18960        let title = multibuffer.title(cx).to_string();
18961
18962        let locations = self
18963            .selections
18964            .all_anchors(cx)
18965            .into_iter()
18966            .map(|selection| Location {
18967                buffer: buffer.clone(),
18968                range: selection.start.text_anchor..selection.end.text_anchor,
18969            })
18970            .collect::<Vec<_>>();
18971
18972        cx.spawn_in(window, async move |_, cx| {
18973            workspace.update_in(cx, |workspace, window, cx| {
18974                Self::open_locations_in_multibuffer(
18975                    workspace,
18976                    locations,
18977                    format!("Selections for '{title}'"),
18978                    false,
18979                    MultibufferSelectionMode::All,
18980                    window,
18981                    cx,
18982                );
18983            })
18984        })
18985        .detach();
18986    }
18987
18988    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18989    /// last highlight added will be used.
18990    ///
18991    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18992    pub fn highlight_rows<T: 'static>(
18993        &mut self,
18994        range: Range<Anchor>,
18995        color: Hsla,
18996        options: RowHighlightOptions,
18997        cx: &mut Context<Self>,
18998    ) {
18999        let snapshot = self.buffer().read(cx).snapshot(cx);
19000        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19001        let ix = row_highlights.binary_search_by(|highlight| {
19002            Ordering::Equal
19003                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19004                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19005        });
19006
19007        if let Err(mut ix) = ix {
19008            let index = post_inc(&mut self.highlight_order);
19009
19010            // If this range intersects with the preceding highlight, then merge it with
19011            // the preceding highlight. Otherwise insert a new highlight.
19012            let mut merged = false;
19013            if ix > 0 {
19014                let prev_highlight = &mut row_highlights[ix - 1];
19015                if prev_highlight
19016                    .range
19017                    .end
19018                    .cmp(&range.start, &snapshot)
19019                    .is_ge()
19020                {
19021                    ix -= 1;
19022                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19023                        prev_highlight.range.end = range.end;
19024                    }
19025                    merged = true;
19026                    prev_highlight.index = index;
19027                    prev_highlight.color = color;
19028                    prev_highlight.options = options;
19029                }
19030            }
19031
19032            if !merged {
19033                row_highlights.insert(
19034                    ix,
19035                    RowHighlight {
19036                        range: range.clone(),
19037                        index,
19038                        color,
19039                        options,
19040                        type_id: TypeId::of::<T>(),
19041                    },
19042                );
19043            }
19044
19045            // If any of the following highlights intersect with this one, merge them.
19046            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19047                let highlight = &row_highlights[ix];
19048                if next_highlight
19049                    .range
19050                    .start
19051                    .cmp(&highlight.range.end, &snapshot)
19052                    .is_le()
19053                {
19054                    if next_highlight
19055                        .range
19056                        .end
19057                        .cmp(&highlight.range.end, &snapshot)
19058                        .is_gt()
19059                    {
19060                        row_highlights[ix].range.end = next_highlight.range.end;
19061                    }
19062                    row_highlights.remove(ix + 1);
19063                } else {
19064                    break;
19065                }
19066            }
19067        }
19068    }
19069
19070    /// Remove any highlighted row ranges of the given type that intersect the
19071    /// given ranges.
19072    pub fn remove_highlighted_rows<T: 'static>(
19073        &mut self,
19074        ranges_to_remove: Vec<Range<Anchor>>,
19075        cx: &mut Context<Self>,
19076    ) {
19077        let snapshot = self.buffer().read(cx).snapshot(cx);
19078        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19079        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19080        row_highlights.retain(|highlight| {
19081            while let Some(range_to_remove) = ranges_to_remove.peek() {
19082                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19083                    Ordering::Less | Ordering::Equal => {
19084                        ranges_to_remove.next();
19085                    }
19086                    Ordering::Greater => {
19087                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19088                            Ordering::Less | Ordering::Equal => {
19089                                return false;
19090                            }
19091                            Ordering::Greater => break,
19092                        }
19093                    }
19094                }
19095            }
19096
19097            true
19098        })
19099    }
19100
19101    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19102    pub fn clear_row_highlights<T: 'static>(&mut self) {
19103        self.highlighted_rows.remove(&TypeId::of::<T>());
19104    }
19105
19106    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19107    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19108        self.highlighted_rows
19109            .get(&TypeId::of::<T>())
19110            .map_or(&[] as &[_], |vec| vec.as_slice())
19111            .iter()
19112            .map(|highlight| (highlight.range.clone(), highlight.color))
19113    }
19114
19115    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19116    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19117    /// Allows to ignore certain kinds of highlights.
19118    pub fn highlighted_display_rows(
19119        &self,
19120        window: &mut Window,
19121        cx: &mut App,
19122    ) -> BTreeMap<DisplayRow, LineHighlight> {
19123        let snapshot = self.snapshot(window, cx);
19124        let mut used_highlight_orders = HashMap::default();
19125        self.highlighted_rows
19126            .iter()
19127            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19128            .fold(
19129                BTreeMap::<DisplayRow, LineHighlight>::new(),
19130                |mut unique_rows, highlight| {
19131                    let start = highlight.range.start.to_display_point(&snapshot);
19132                    let end = highlight.range.end.to_display_point(&snapshot);
19133                    let start_row = start.row().0;
19134                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19135                        && end.column() == 0
19136                    {
19137                        end.row().0.saturating_sub(1)
19138                    } else {
19139                        end.row().0
19140                    };
19141                    for row in start_row..=end_row {
19142                        let used_index =
19143                            used_highlight_orders.entry(row).or_insert(highlight.index);
19144                        if highlight.index >= *used_index {
19145                            *used_index = highlight.index;
19146                            unique_rows.insert(
19147                                DisplayRow(row),
19148                                LineHighlight {
19149                                    include_gutter: highlight.options.include_gutter,
19150                                    border: None,
19151                                    background: highlight.color.into(),
19152                                    type_id: Some(highlight.type_id),
19153                                },
19154                            );
19155                        }
19156                    }
19157                    unique_rows
19158                },
19159            )
19160    }
19161
19162    pub fn highlighted_display_row_for_autoscroll(
19163        &self,
19164        snapshot: &DisplaySnapshot,
19165    ) -> Option<DisplayRow> {
19166        self.highlighted_rows
19167            .values()
19168            .flat_map(|highlighted_rows| highlighted_rows.iter())
19169            .filter_map(|highlight| {
19170                if highlight.options.autoscroll {
19171                    Some(highlight.range.start.to_display_point(snapshot).row())
19172                } else {
19173                    None
19174                }
19175            })
19176            .min()
19177    }
19178
19179    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19180        self.highlight_background::<SearchWithinRange>(
19181            ranges,
19182            |colors| colors.colors().editor_document_highlight_read_background,
19183            cx,
19184        )
19185    }
19186
19187    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19188        self.breadcrumb_header = Some(new_header);
19189    }
19190
19191    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19192        self.clear_background_highlights::<SearchWithinRange>(cx);
19193    }
19194
19195    pub fn highlight_background<T: 'static>(
19196        &mut self,
19197        ranges: &[Range<Anchor>],
19198        color_fetcher: fn(&Theme) -> Hsla,
19199        cx: &mut Context<Self>,
19200    ) {
19201        self.background_highlights.insert(
19202            HighlightKey::Type(TypeId::of::<T>()),
19203            (color_fetcher, Arc::from(ranges)),
19204        );
19205        self.scrollbar_marker_state.dirty = true;
19206        cx.notify();
19207    }
19208
19209    pub fn highlight_background_key<T: 'static>(
19210        &mut self,
19211        key: usize,
19212        ranges: &[Range<Anchor>],
19213        color_fetcher: fn(&Theme) -> Hsla,
19214        cx: &mut Context<Self>,
19215    ) {
19216        self.background_highlights.insert(
19217            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19218            (color_fetcher, Arc::from(ranges)),
19219        );
19220        self.scrollbar_marker_state.dirty = true;
19221        cx.notify();
19222    }
19223
19224    pub fn clear_background_highlights<T: 'static>(
19225        &mut self,
19226        cx: &mut Context<Self>,
19227    ) -> Option<BackgroundHighlight> {
19228        let text_highlights = self
19229            .background_highlights
19230            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19231        if !text_highlights.1.is_empty() {
19232            self.scrollbar_marker_state.dirty = true;
19233            cx.notify();
19234        }
19235        Some(text_highlights)
19236    }
19237
19238    pub fn highlight_gutter<T: 'static>(
19239        &mut self,
19240        ranges: impl Into<Vec<Range<Anchor>>>,
19241        color_fetcher: fn(&App) -> Hsla,
19242        cx: &mut Context<Self>,
19243    ) {
19244        self.gutter_highlights
19245            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19246        cx.notify();
19247    }
19248
19249    pub fn clear_gutter_highlights<T: 'static>(
19250        &mut self,
19251        cx: &mut Context<Self>,
19252    ) -> Option<GutterHighlight> {
19253        cx.notify();
19254        self.gutter_highlights.remove(&TypeId::of::<T>())
19255    }
19256
19257    pub fn insert_gutter_highlight<T: 'static>(
19258        &mut self,
19259        range: Range<Anchor>,
19260        color_fetcher: fn(&App) -> Hsla,
19261        cx: &mut Context<Self>,
19262    ) {
19263        let snapshot = self.buffer().read(cx).snapshot(cx);
19264        let mut highlights = self
19265            .gutter_highlights
19266            .remove(&TypeId::of::<T>())
19267            .map(|(_, highlights)| highlights)
19268            .unwrap_or_default();
19269        let ix = highlights.binary_search_by(|highlight| {
19270            Ordering::Equal
19271                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19272                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19273        });
19274        if let Err(ix) = ix {
19275            highlights.insert(ix, range);
19276        }
19277        self.gutter_highlights
19278            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19279    }
19280
19281    pub fn remove_gutter_highlights<T: 'static>(
19282        &mut self,
19283        ranges_to_remove: Vec<Range<Anchor>>,
19284        cx: &mut Context<Self>,
19285    ) {
19286        let snapshot = self.buffer().read(cx).snapshot(cx);
19287        let Some((color_fetcher, mut gutter_highlights)) =
19288            self.gutter_highlights.remove(&TypeId::of::<T>())
19289        else {
19290            return;
19291        };
19292        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19293        gutter_highlights.retain(|highlight| {
19294            while let Some(range_to_remove) = ranges_to_remove.peek() {
19295                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19296                    Ordering::Less | Ordering::Equal => {
19297                        ranges_to_remove.next();
19298                    }
19299                    Ordering::Greater => {
19300                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19301                            Ordering::Less | Ordering::Equal => {
19302                                return false;
19303                            }
19304                            Ordering::Greater => break,
19305                        }
19306                    }
19307                }
19308            }
19309
19310            true
19311        });
19312        self.gutter_highlights
19313            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19314    }
19315
19316    #[cfg(feature = "test-support")]
19317    pub fn all_text_highlights(
19318        &self,
19319        window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19322        let snapshot = self.snapshot(window, cx);
19323        self.display_map.update(cx, |display_map, _| {
19324            display_map
19325                .all_text_highlights()
19326                .map(|highlight| {
19327                    let (style, ranges) = highlight.as_ref();
19328                    (
19329                        *style,
19330                        ranges
19331                            .iter()
19332                            .map(|range| range.clone().to_display_points(&snapshot))
19333                            .collect(),
19334                    )
19335                })
19336                .collect()
19337        })
19338    }
19339
19340    #[cfg(feature = "test-support")]
19341    pub fn all_text_background_highlights(
19342        &self,
19343        window: &mut Window,
19344        cx: &mut Context<Self>,
19345    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19346        let snapshot = self.snapshot(window, cx);
19347        let buffer = &snapshot.buffer_snapshot;
19348        let start = buffer.anchor_before(0);
19349        let end = buffer.anchor_after(buffer.len());
19350        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19351    }
19352
19353    #[cfg(feature = "test-support")]
19354    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19355        let snapshot = self.buffer().read(cx).snapshot(cx);
19356
19357        let highlights = self
19358            .background_highlights
19359            .get(&HighlightKey::Type(TypeId::of::<
19360                items::BufferSearchHighlights,
19361            >()));
19362
19363        if let Some((_color, ranges)) = highlights {
19364            ranges
19365                .iter()
19366                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19367                .collect_vec()
19368        } else {
19369            vec![]
19370        }
19371    }
19372
19373    fn document_highlights_for_position<'a>(
19374        &'a self,
19375        position: Anchor,
19376        buffer: &'a MultiBufferSnapshot,
19377    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19378        let read_highlights = self
19379            .background_highlights
19380            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19381            .map(|h| &h.1);
19382        let write_highlights = self
19383            .background_highlights
19384            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19385            .map(|h| &h.1);
19386        let left_position = position.bias_left(buffer);
19387        let right_position = position.bias_right(buffer);
19388        read_highlights
19389            .into_iter()
19390            .chain(write_highlights)
19391            .flat_map(move |ranges| {
19392                let start_ix = match ranges.binary_search_by(|probe| {
19393                    let cmp = probe.end.cmp(&left_position, buffer);
19394                    if cmp.is_ge() {
19395                        Ordering::Greater
19396                    } else {
19397                        Ordering::Less
19398                    }
19399                }) {
19400                    Ok(i) | Err(i) => i,
19401                };
19402
19403                ranges[start_ix..]
19404                    .iter()
19405                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19406            })
19407    }
19408
19409    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19410        self.background_highlights
19411            .get(&HighlightKey::Type(TypeId::of::<T>()))
19412            .map_or(false, |(_, highlights)| !highlights.is_empty())
19413    }
19414
19415    pub fn background_highlights_in_range(
19416        &self,
19417        search_range: Range<Anchor>,
19418        display_snapshot: &DisplaySnapshot,
19419        theme: &Theme,
19420    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19421        let mut results = Vec::new();
19422        for (color_fetcher, ranges) in self.background_highlights.values() {
19423            let color = color_fetcher(theme);
19424            let start_ix = match ranges.binary_search_by(|probe| {
19425                let cmp = probe
19426                    .end
19427                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19428                if cmp.is_gt() {
19429                    Ordering::Greater
19430                } else {
19431                    Ordering::Less
19432                }
19433            }) {
19434                Ok(i) | Err(i) => i,
19435            };
19436            for range in &ranges[start_ix..] {
19437                if range
19438                    .start
19439                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19440                    .is_ge()
19441                {
19442                    break;
19443                }
19444
19445                let start = range.start.to_display_point(display_snapshot);
19446                let end = range.end.to_display_point(display_snapshot);
19447                results.push((start..end, color))
19448            }
19449        }
19450        results
19451    }
19452
19453    pub fn background_highlight_row_ranges<T: 'static>(
19454        &self,
19455        search_range: Range<Anchor>,
19456        display_snapshot: &DisplaySnapshot,
19457        count: usize,
19458    ) -> Vec<RangeInclusive<DisplayPoint>> {
19459        let mut results = Vec::new();
19460        let Some((_, ranges)) = self
19461            .background_highlights
19462            .get(&HighlightKey::Type(TypeId::of::<T>()))
19463        else {
19464            return vec![];
19465        };
19466
19467        let start_ix = match ranges.binary_search_by(|probe| {
19468            let cmp = probe
19469                .end
19470                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19471            if cmp.is_gt() {
19472                Ordering::Greater
19473            } else {
19474                Ordering::Less
19475            }
19476        }) {
19477            Ok(i) | Err(i) => i,
19478        };
19479        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19480            if let (Some(start_display), Some(end_display)) = (start, end) {
19481                results.push(
19482                    start_display.to_display_point(display_snapshot)
19483                        ..=end_display.to_display_point(display_snapshot),
19484                );
19485            }
19486        };
19487        let mut start_row: Option<Point> = None;
19488        let mut end_row: Option<Point> = None;
19489        if ranges.len() > count {
19490            return Vec::new();
19491        }
19492        for range in &ranges[start_ix..] {
19493            if range
19494                .start
19495                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19496                .is_ge()
19497            {
19498                break;
19499            }
19500            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19501            if let Some(current_row) = &end_row {
19502                if end.row == current_row.row {
19503                    continue;
19504                }
19505            }
19506            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19507            if start_row.is_none() {
19508                assert_eq!(end_row, None);
19509                start_row = Some(start);
19510                end_row = Some(end);
19511                continue;
19512            }
19513            if let Some(current_end) = end_row.as_mut() {
19514                if start.row > current_end.row + 1 {
19515                    push_region(start_row, end_row);
19516                    start_row = Some(start);
19517                    end_row = Some(end);
19518                } else {
19519                    // Merge two hunks.
19520                    *current_end = end;
19521                }
19522            } else {
19523                unreachable!();
19524            }
19525        }
19526        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19527        push_region(start_row, end_row);
19528        results
19529    }
19530
19531    pub fn gutter_highlights_in_range(
19532        &self,
19533        search_range: Range<Anchor>,
19534        display_snapshot: &DisplaySnapshot,
19535        cx: &App,
19536    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19537        let mut results = Vec::new();
19538        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19539            let color = color_fetcher(cx);
19540            let start_ix = match ranges.binary_search_by(|probe| {
19541                let cmp = probe
19542                    .end
19543                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19544                if cmp.is_gt() {
19545                    Ordering::Greater
19546                } else {
19547                    Ordering::Less
19548                }
19549            }) {
19550                Ok(i) | Err(i) => i,
19551            };
19552            for range in &ranges[start_ix..] {
19553                if range
19554                    .start
19555                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19556                    .is_ge()
19557                {
19558                    break;
19559                }
19560
19561                let start = range.start.to_display_point(display_snapshot);
19562                let end = range.end.to_display_point(display_snapshot);
19563                results.push((start..end, color))
19564            }
19565        }
19566        results
19567    }
19568
19569    /// Get the text ranges corresponding to the redaction query
19570    pub fn redacted_ranges(
19571        &self,
19572        search_range: Range<Anchor>,
19573        display_snapshot: &DisplaySnapshot,
19574        cx: &App,
19575    ) -> Vec<Range<DisplayPoint>> {
19576        display_snapshot
19577            .buffer_snapshot
19578            .redacted_ranges(search_range, |file| {
19579                if let Some(file) = file {
19580                    file.is_private()
19581                        && EditorSettings::get(
19582                            Some(SettingsLocation {
19583                                worktree_id: file.worktree_id(cx),
19584                                path: file.path().as_ref(),
19585                            }),
19586                            cx,
19587                        )
19588                        .redact_private_values
19589                } else {
19590                    false
19591                }
19592            })
19593            .map(|range| {
19594                range.start.to_display_point(display_snapshot)
19595                    ..range.end.to_display_point(display_snapshot)
19596            })
19597            .collect()
19598    }
19599
19600    pub fn highlight_text_key<T: 'static>(
19601        &mut self,
19602        key: usize,
19603        ranges: Vec<Range<Anchor>>,
19604        style: HighlightStyle,
19605        cx: &mut Context<Self>,
19606    ) {
19607        self.display_map.update(cx, |map, _| {
19608            map.highlight_text(
19609                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19610                ranges,
19611                style,
19612            );
19613        });
19614        cx.notify();
19615    }
19616
19617    pub fn highlight_text<T: 'static>(
19618        &mut self,
19619        ranges: Vec<Range<Anchor>>,
19620        style: HighlightStyle,
19621        cx: &mut Context<Self>,
19622    ) {
19623        self.display_map.update(cx, |map, _| {
19624            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19625        });
19626        cx.notify();
19627    }
19628
19629    pub(crate) fn highlight_inlays<T: 'static>(
19630        &mut self,
19631        highlights: Vec<InlayHighlight>,
19632        style: HighlightStyle,
19633        cx: &mut Context<Self>,
19634    ) {
19635        self.display_map.update(cx, |map, _| {
19636            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19637        });
19638        cx.notify();
19639    }
19640
19641    pub fn text_highlights<'a, T: 'static>(
19642        &'a self,
19643        cx: &'a App,
19644    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19645        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19646    }
19647
19648    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19649        let cleared = self
19650            .display_map
19651            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19652        if cleared {
19653            cx.notify();
19654        }
19655    }
19656
19657    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19658        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19659            && self.focus_handle.is_focused(window)
19660    }
19661
19662    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19663        self.show_cursor_when_unfocused = is_enabled;
19664        cx.notify();
19665    }
19666
19667    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19668        cx.notify();
19669    }
19670
19671    fn on_debug_session_event(
19672        &mut self,
19673        _session: Entity<Session>,
19674        event: &SessionEvent,
19675        cx: &mut Context<Self>,
19676    ) {
19677        match event {
19678            SessionEvent::InvalidateInlineValue => {
19679                self.refresh_inline_values(cx);
19680            }
19681            _ => {}
19682        }
19683    }
19684
19685    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19686        let Some(project) = self.project.clone() else {
19687            return;
19688        };
19689
19690        if !self.inline_value_cache.enabled {
19691            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19692            self.splice_inlays(&inlays, Vec::new(), cx);
19693            return;
19694        }
19695
19696        let current_execution_position = self
19697            .highlighted_rows
19698            .get(&TypeId::of::<ActiveDebugLine>())
19699            .and_then(|lines| lines.last().map(|line| line.range.end));
19700
19701        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19702            let inline_values = editor
19703                .update(cx, |editor, cx| {
19704                    let Some(current_execution_position) = current_execution_position else {
19705                        return Some(Task::ready(Ok(Vec::new())));
19706                    };
19707
19708                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19709                        let snapshot = buffer.snapshot(cx);
19710
19711                        let excerpt = snapshot.excerpt_containing(
19712                            current_execution_position..current_execution_position,
19713                        )?;
19714
19715                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19716                    })?;
19717
19718                    let range =
19719                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19720
19721                    project.inline_values(buffer, range, cx)
19722                })
19723                .ok()
19724                .flatten()?
19725                .await
19726                .context("refreshing debugger inlays")
19727                .log_err()?;
19728
19729            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19730
19731            for (buffer_id, inline_value) in inline_values
19732                .into_iter()
19733                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19734            {
19735                buffer_inline_values
19736                    .entry(buffer_id)
19737                    .or_default()
19738                    .push(inline_value);
19739            }
19740
19741            editor
19742                .update(cx, |editor, cx| {
19743                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19744                    let mut new_inlays = Vec::default();
19745
19746                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19747                        let buffer_id = buffer_snapshot.remote_id();
19748                        buffer_inline_values
19749                            .get(&buffer_id)
19750                            .into_iter()
19751                            .flatten()
19752                            .for_each(|hint| {
19753                                let inlay = Inlay::debugger(
19754                                    post_inc(&mut editor.next_inlay_id),
19755                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19756                                    hint.text(),
19757                                );
19758                                if !inlay.text.chars().contains(&'\n') {
19759                                    new_inlays.push(inlay);
19760                                }
19761                            });
19762                    }
19763
19764                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19765                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19766
19767                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19768                })
19769                .ok()?;
19770            Some(())
19771        });
19772    }
19773
19774    fn on_buffer_event(
19775        &mut self,
19776        multibuffer: &Entity<MultiBuffer>,
19777        event: &multi_buffer::Event,
19778        window: &mut Window,
19779        cx: &mut Context<Self>,
19780    ) {
19781        match event {
19782            multi_buffer::Event::Edited {
19783                singleton_buffer_edited,
19784                edited_buffer,
19785            } => {
19786                self.scrollbar_marker_state.dirty = true;
19787                self.active_indent_guides_state.dirty = true;
19788                self.refresh_active_diagnostics(cx);
19789                self.refresh_code_actions(window, cx);
19790                self.refresh_selected_text_highlights(true, window, cx);
19791                self.refresh_single_line_folds(window, cx);
19792                refresh_matching_bracket_highlights(self, window, cx);
19793                if self.has_active_inline_completion() {
19794                    self.update_visible_inline_completion(window, cx);
19795                }
19796                if let Some(project) = self.project.as_ref() {
19797                    if let Some(edited_buffer) = edited_buffer {
19798                        project.update(cx, |project, cx| {
19799                            self.registered_buffers
19800                                .entry(edited_buffer.read(cx).remote_id())
19801                                .or_insert_with(|| {
19802                                    project
19803                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19804                                });
19805                        });
19806                    }
19807                }
19808                cx.emit(EditorEvent::BufferEdited);
19809                cx.emit(SearchEvent::MatchesInvalidated);
19810
19811                if let Some(buffer) = edited_buffer {
19812                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19813                }
19814
19815                if *singleton_buffer_edited {
19816                    if let Some(buffer) = edited_buffer {
19817                        if buffer.read(cx).file().is_none() {
19818                            cx.emit(EditorEvent::TitleChanged);
19819                        }
19820                    }
19821                    if let Some(project) = &self.project {
19822                        #[allow(clippy::mutable_key_type)]
19823                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19824                            multibuffer
19825                                .all_buffers()
19826                                .into_iter()
19827                                .filter_map(|buffer| {
19828                                    buffer.update(cx, |buffer, cx| {
19829                                        let language = buffer.language()?;
19830                                        let should_discard = project.update(cx, |project, cx| {
19831                                            project.is_local()
19832                                                && !project.has_language_servers_for(buffer, cx)
19833                                        });
19834                                        should_discard.not().then_some(language.clone())
19835                                    })
19836                                })
19837                                .collect::<HashSet<_>>()
19838                        });
19839                        if !languages_affected.is_empty() {
19840                            self.refresh_inlay_hints(
19841                                InlayHintRefreshReason::BufferEdited(languages_affected),
19842                                cx,
19843                            );
19844                        }
19845                    }
19846                }
19847
19848                let Some(project) = &self.project else { return };
19849                let (telemetry, is_via_ssh) = {
19850                    let project = project.read(cx);
19851                    let telemetry = project.client().telemetry().clone();
19852                    let is_via_ssh = project.is_via_ssh();
19853                    (telemetry, is_via_ssh)
19854                };
19855                refresh_linked_ranges(self, window, cx);
19856                telemetry.log_edit_event("editor", is_via_ssh);
19857            }
19858            multi_buffer::Event::ExcerptsAdded {
19859                buffer,
19860                predecessor,
19861                excerpts,
19862            } => {
19863                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19864                let buffer_id = buffer.read(cx).remote_id();
19865                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19866                    if let Some(project) = &self.project {
19867                        update_uncommitted_diff_for_buffer(
19868                            cx.entity(),
19869                            project,
19870                            [buffer.clone()],
19871                            self.buffer.clone(),
19872                            cx,
19873                        )
19874                        .detach();
19875                    }
19876                }
19877                self.update_lsp_data(false, Some(buffer_id), window, cx);
19878                cx.emit(EditorEvent::ExcerptsAdded {
19879                    buffer: buffer.clone(),
19880                    predecessor: *predecessor,
19881                    excerpts: excerpts.clone(),
19882                });
19883                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19884            }
19885            multi_buffer::Event::ExcerptsRemoved {
19886                ids,
19887                removed_buffer_ids,
19888            } => {
19889                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19890                let buffer = self.buffer.read(cx);
19891                self.registered_buffers
19892                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19893                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19894                cx.emit(EditorEvent::ExcerptsRemoved {
19895                    ids: ids.clone(),
19896                    removed_buffer_ids: removed_buffer_ids.clone(),
19897                });
19898            }
19899            multi_buffer::Event::ExcerptsEdited {
19900                excerpt_ids,
19901                buffer_ids,
19902            } => {
19903                self.display_map.update(cx, |map, cx| {
19904                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19905                });
19906                cx.emit(EditorEvent::ExcerptsEdited {
19907                    ids: excerpt_ids.clone(),
19908                });
19909            }
19910            multi_buffer::Event::ExcerptsExpanded { ids } => {
19911                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19912                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19913            }
19914            multi_buffer::Event::Reparsed(buffer_id) => {
19915                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19916                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19917
19918                cx.emit(EditorEvent::Reparsed(*buffer_id));
19919            }
19920            multi_buffer::Event::DiffHunksToggled => {
19921                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19922            }
19923            multi_buffer::Event::LanguageChanged(buffer_id) => {
19924                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19925                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19926                cx.emit(EditorEvent::Reparsed(*buffer_id));
19927                cx.notify();
19928            }
19929            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19930            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19931            multi_buffer::Event::FileHandleChanged
19932            | multi_buffer::Event::Reloaded
19933            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19934            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19935            multi_buffer::Event::DiagnosticsUpdated => {
19936                self.update_diagnostics_state(window, cx);
19937            }
19938            _ => {}
19939        };
19940    }
19941
19942    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19943        if !self.diagnostics_enabled() {
19944            return;
19945        }
19946        self.refresh_active_diagnostics(cx);
19947        self.refresh_inline_diagnostics(true, window, cx);
19948        self.scrollbar_marker_state.dirty = true;
19949        cx.notify();
19950    }
19951
19952    pub fn start_temporary_diff_override(&mut self) {
19953        self.load_diff_task.take();
19954        self.temporary_diff_override = true;
19955    }
19956
19957    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19958        self.temporary_diff_override = false;
19959        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19960        self.buffer.update(cx, |buffer, cx| {
19961            buffer.set_all_diff_hunks_collapsed(cx);
19962        });
19963
19964        if let Some(project) = self.project.clone() {
19965            self.load_diff_task = Some(
19966                update_uncommitted_diff_for_buffer(
19967                    cx.entity(),
19968                    &project,
19969                    self.buffer.read(cx).all_buffers(),
19970                    self.buffer.clone(),
19971                    cx,
19972                )
19973                .shared(),
19974            );
19975        }
19976    }
19977
19978    fn on_display_map_changed(
19979        &mut self,
19980        _: Entity<DisplayMap>,
19981        _: &mut Window,
19982        cx: &mut Context<Self>,
19983    ) {
19984        cx.notify();
19985    }
19986
19987    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19988        if self.diagnostics_enabled() {
19989            let new_severity = EditorSettings::get_global(cx)
19990                .diagnostics_max_severity
19991                .unwrap_or(DiagnosticSeverity::Hint);
19992            self.set_max_diagnostics_severity(new_severity, cx);
19993        }
19994        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19995        self.update_edit_prediction_settings(cx);
19996        self.refresh_inline_completion(true, false, window, cx);
19997        self.refresh_inline_values(cx);
19998        self.refresh_inlay_hints(
19999            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20000                self.selections.newest_anchor().head(),
20001                &self.buffer.read(cx).snapshot(cx),
20002                cx,
20003            )),
20004            cx,
20005        );
20006
20007        let old_cursor_shape = self.cursor_shape;
20008
20009        {
20010            let editor_settings = EditorSettings::get_global(cx);
20011            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20012            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20013            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20014            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20015        }
20016
20017        if old_cursor_shape != self.cursor_shape {
20018            cx.emit(EditorEvent::CursorShapeChanged);
20019        }
20020
20021        let project_settings = ProjectSettings::get_global(cx);
20022        self.serialize_dirty_buffers =
20023            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20024
20025        if self.mode.is_full() {
20026            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20027            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20028            if self.show_inline_diagnostics != show_inline_diagnostics {
20029                self.show_inline_diagnostics = show_inline_diagnostics;
20030                self.refresh_inline_diagnostics(false, window, cx);
20031            }
20032
20033            if self.git_blame_inline_enabled != inline_blame_enabled {
20034                self.toggle_git_blame_inline_internal(false, window, cx);
20035            }
20036
20037            let minimap_settings = EditorSettings::get_global(cx).minimap;
20038            if self.minimap_visibility != MinimapVisibility::Disabled {
20039                if self.minimap_visibility.settings_visibility()
20040                    != minimap_settings.minimap_enabled()
20041                {
20042                    self.set_minimap_visibility(
20043                        MinimapVisibility::for_mode(self.mode(), cx),
20044                        window,
20045                        cx,
20046                    );
20047                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20048                    minimap_entity.update(cx, |minimap_editor, cx| {
20049                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20050                    })
20051                }
20052            }
20053        }
20054
20055        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20056            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20057        }) {
20058            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20059                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20060            }
20061            self.refresh_colors(false, None, window, cx);
20062        }
20063
20064        cx.notify();
20065    }
20066
20067    pub fn set_searchable(&mut self, searchable: bool) {
20068        self.searchable = searchable;
20069    }
20070
20071    pub fn searchable(&self) -> bool {
20072        self.searchable
20073    }
20074
20075    fn open_proposed_changes_editor(
20076        &mut self,
20077        _: &OpenProposedChangesEditor,
20078        window: &mut Window,
20079        cx: &mut Context<Self>,
20080    ) {
20081        let Some(workspace) = self.workspace() else {
20082            cx.propagate();
20083            return;
20084        };
20085
20086        let selections = self.selections.all::<usize>(cx);
20087        let multi_buffer = self.buffer.read(cx);
20088        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20089        let mut new_selections_by_buffer = HashMap::default();
20090        for selection in selections {
20091            for (buffer, range, _) in
20092                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20093            {
20094                let mut range = range.to_point(buffer);
20095                range.start.column = 0;
20096                range.end.column = buffer.line_len(range.end.row);
20097                new_selections_by_buffer
20098                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20099                    .or_insert(Vec::new())
20100                    .push(range)
20101            }
20102        }
20103
20104        let proposed_changes_buffers = new_selections_by_buffer
20105            .into_iter()
20106            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20107            .collect::<Vec<_>>();
20108        let proposed_changes_editor = cx.new(|cx| {
20109            ProposedChangesEditor::new(
20110                "Proposed changes",
20111                proposed_changes_buffers,
20112                self.project.clone(),
20113                window,
20114                cx,
20115            )
20116        });
20117
20118        window.defer(cx, move |window, cx| {
20119            workspace.update(cx, |workspace, cx| {
20120                workspace.active_pane().update(cx, |pane, cx| {
20121                    pane.add_item(
20122                        Box::new(proposed_changes_editor),
20123                        true,
20124                        true,
20125                        None,
20126                        window,
20127                        cx,
20128                    );
20129                });
20130            });
20131        });
20132    }
20133
20134    pub fn open_excerpts_in_split(
20135        &mut self,
20136        _: &OpenExcerptsSplit,
20137        window: &mut Window,
20138        cx: &mut Context<Self>,
20139    ) {
20140        self.open_excerpts_common(None, true, window, cx)
20141    }
20142
20143    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20144        self.open_excerpts_common(None, false, window, cx)
20145    }
20146
20147    fn open_excerpts_common(
20148        &mut self,
20149        jump_data: Option<JumpData>,
20150        split: bool,
20151        window: &mut Window,
20152        cx: &mut Context<Self>,
20153    ) {
20154        let Some(workspace) = self.workspace() else {
20155            cx.propagate();
20156            return;
20157        };
20158
20159        if self.buffer.read(cx).is_singleton() {
20160            cx.propagate();
20161            return;
20162        }
20163
20164        let mut new_selections_by_buffer = HashMap::default();
20165        match &jump_data {
20166            Some(JumpData::MultiBufferPoint {
20167                excerpt_id,
20168                position,
20169                anchor,
20170                line_offset_from_top,
20171            }) => {
20172                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20173                if let Some(buffer) = multi_buffer_snapshot
20174                    .buffer_id_for_excerpt(*excerpt_id)
20175                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20176                {
20177                    let buffer_snapshot = buffer.read(cx).snapshot();
20178                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20179                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20180                    } else {
20181                        buffer_snapshot.clip_point(*position, Bias::Left)
20182                    };
20183                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20184                    new_selections_by_buffer.insert(
20185                        buffer,
20186                        (
20187                            vec![jump_to_offset..jump_to_offset],
20188                            Some(*line_offset_from_top),
20189                        ),
20190                    );
20191                }
20192            }
20193            Some(JumpData::MultiBufferRow {
20194                row,
20195                line_offset_from_top,
20196            }) => {
20197                let point = MultiBufferPoint::new(row.0, 0);
20198                if let Some((buffer, buffer_point, _)) =
20199                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20200                {
20201                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20202                    new_selections_by_buffer
20203                        .entry(buffer)
20204                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20205                        .0
20206                        .push(buffer_offset..buffer_offset)
20207                }
20208            }
20209            None => {
20210                let selections = self.selections.all::<usize>(cx);
20211                let multi_buffer = self.buffer.read(cx);
20212                for selection in selections {
20213                    for (snapshot, range, _, anchor) in multi_buffer
20214                        .snapshot(cx)
20215                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20216                    {
20217                        if let Some(anchor) = anchor {
20218                            // selection is in a deleted hunk
20219                            let Some(buffer_id) = anchor.buffer_id else {
20220                                continue;
20221                            };
20222                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20223                                continue;
20224                            };
20225                            let offset = text::ToOffset::to_offset(
20226                                &anchor.text_anchor,
20227                                &buffer_handle.read(cx).snapshot(),
20228                            );
20229                            let range = offset..offset;
20230                            new_selections_by_buffer
20231                                .entry(buffer_handle)
20232                                .or_insert((Vec::new(), None))
20233                                .0
20234                                .push(range)
20235                        } else {
20236                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20237                            else {
20238                                continue;
20239                            };
20240                            new_selections_by_buffer
20241                                .entry(buffer_handle)
20242                                .or_insert((Vec::new(), None))
20243                                .0
20244                                .push(range)
20245                        }
20246                    }
20247                }
20248            }
20249        }
20250
20251        new_selections_by_buffer
20252            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20253
20254        if new_selections_by_buffer.is_empty() {
20255            return;
20256        }
20257
20258        // We defer the pane interaction because we ourselves are a workspace item
20259        // and activating a new item causes the pane to call a method on us reentrantly,
20260        // which panics if we're on the stack.
20261        window.defer(cx, move |window, cx| {
20262            workspace.update(cx, |workspace, cx| {
20263                let pane = if split {
20264                    workspace.adjacent_pane(window, cx)
20265                } else {
20266                    workspace.active_pane().clone()
20267                };
20268
20269                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20270                    let editor = buffer
20271                        .read(cx)
20272                        .file()
20273                        .is_none()
20274                        .then(|| {
20275                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20276                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20277                            // Instead, we try to activate the existing editor in the pane first.
20278                            let (editor, pane_item_index) =
20279                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20280                                    let editor = item.downcast::<Editor>()?;
20281                                    let singleton_buffer =
20282                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20283                                    if singleton_buffer == buffer {
20284                                        Some((editor, i))
20285                                    } else {
20286                                        None
20287                                    }
20288                                })?;
20289                            pane.update(cx, |pane, cx| {
20290                                pane.activate_item(pane_item_index, true, true, window, cx)
20291                            });
20292                            Some(editor)
20293                        })
20294                        .flatten()
20295                        .unwrap_or_else(|| {
20296                            workspace.open_project_item::<Self>(
20297                                pane.clone(),
20298                                buffer,
20299                                true,
20300                                true,
20301                                window,
20302                                cx,
20303                            )
20304                        });
20305
20306                    editor.update(cx, |editor, cx| {
20307                        let autoscroll = match scroll_offset {
20308                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20309                            None => Autoscroll::newest(),
20310                        };
20311                        let nav_history = editor.nav_history.take();
20312                        editor.change_selections(
20313                            SelectionEffects::scroll(autoscroll),
20314                            window,
20315                            cx,
20316                            |s| {
20317                                s.select_ranges(ranges);
20318                            },
20319                        );
20320                        editor.nav_history = nav_history;
20321                    });
20322                }
20323            })
20324        });
20325    }
20326
20327    // For now, don't allow opening excerpts in buffers that aren't backed by
20328    // regular project files.
20329    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20330        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20331    }
20332
20333    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20334        let snapshot = self.buffer.read(cx).read(cx);
20335        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20336        Some(
20337            ranges
20338                .iter()
20339                .map(move |range| {
20340                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20341                })
20342                .collect(),
20343        )
20344    }
20345
20346    fn selection_replacement_ranges(
20347        &self,
20348        range: Range<OffsetUtf16>,
20349        cx: &mut App,
20350    ) -> Vec<Range<OffsetUtf16>> {
20351        let selections = self.selections.all::<OffsetUtf16>(cx);
20352        let newest_selection = selections
20353            .iter()
20354            .max_by_key(|selection| selection.id)
20355            .unwrap();
20356        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20357        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20358        let snapshot = self.buffer.read(cx).read(cx);
20359        selections
20360            .into_iter()
20361            .map(|mut selection| {
20362                selection.start.0 =
20363                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20364                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20365                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20366                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20367            })
20368            .collect()
20369    }
20370
20371    fn report_editor_event(
20372        &self,
20373        event_type: &'static str,
20374        file_extension: Option<String>,
20375        cx: &App,
20376    ) {
20377        if cfg!(any(test, feature = "test-support")) {
20378            return;
20379        }
20380
20381        let Some(project) = &self.project else { return };
20382
20383        // If None, we are in a file without an extension
20384        let file = self
20385            .buffer
20386            .read(cx)
20387            .as_singleton()
20388            .and_then(|b| b.read(cx).file());
20389        let file_extension = file_extension.or(file
20390            .as_ref()
20391            .and_then(|file| Path::new(file.file_name(cx)).extension())
20392            .and_then(|e| e.to_str())
20393            .map(|a| a.to_string()));
20394
20395        let vim_mode = vim_enabled(cx);
20396
20397        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20398        let copilot_enabled = edit_predictions_provider
20399            == language::language_settings::EditPredictionProvider::Copilot;
20400        let copilot_enabled_for_language = self
20401            .buffer
20402            .read(cx)
20403            .language_settings(cx)
20404            .show_edit_predictions;
20405
20406        let project = project.read(cx);
20407        telemetry::event!(
20408            event_type,
20409            file_extension,
20410            vim_mode,
20411            copilot_enabled,
20412            copilot_enabled_for_language,
20413            edit_predictions_provider,
20414            is_via_ssh = project.is_via_ssh(),
20415        );
20416    }
20417
20418    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20419    /// with each line being an array of {text, highlight} objects.
20420    fn copy_highlight_json(
20421        &mut self,
20422        _: &CopyHighlightJson,
20423        window: &mut Window,
20424        cx: &mut Context<Self>,
20425    ) {
20426        #[derive(Serialize)]
20427        struct Chunk<'a> {
20428            text: String,
20429            highlight: Option<&'a str>,
20430        }
20431
20432        let snapshot = self.buffer.read(cx).snapshot(cx);
20433        let range = self
20434            .selected_text_range(false, window, cx)
20435            .and_then(|selection| {
20436                if selection.range.is_empty() {
20437                    None
20438                } else {
20439                    Some(selection.range)
20440                }
20441            })
20442            .unwrap_or_else(|| 0..snapshot.len());
20443
20444        let chunks = snapshot.chunks(range, true);
20445        let mut lines = Vec::new();
20446        let mut line: VecDeque<Chunk> = VecDeque::new();
20447
20448        let Some(style) = self.style.as_ref() else {
20449            return;
20450        };
20451
20452        for chunk in chunks {
20453            let highlight = chunk
20454                .syntax_highlight_id
20455                .and_then(|id| id.name(&style.syntax));
20456            let mut chunk_lines = chunk.text.split('\n').peekable();
20457            while let Some(text) = chunk_lines.next() {
20458                let mut merged_with_last_token = false;
20459                if let Some(last_token) = line.back_mut() {
20460                    if last_token.highlight == highlight {
20461                        last_token.text.push_str(text);
20462                        merged_with_last_token = true;
20463                    }
20464                }
20465
20466                if !merged_with_last_token {
20467                    line.push_back(Chunk {
20468                        text: text.into(),
20469                        highlight,
20470                    });
20471                }
20472
20473                if chunk_lines.peek().is_some() {
20474                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20475                        line.pop_front();
20476                    }
20477                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20478                        line.pop_back();
20479                    }
20480
20481                    lines.push(mem::take(&mut line));
20482                }
20483            }
20484        }
20485
20486        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20487            return;
20488        };
20489        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20490    }
20491
20492    pub fn open_context_menu(
20493        &mut self,
20494        _: &OpenContextMenu,
20495        window: &mut Window,
20496        cx: &mut Context<Self>,
20497    ) {
20498        self.request_autoscroll(Autoscroll::newest(), cx);
20499        let position = self.selections.newest_display(cx).start;
20500        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20501    }
20502
20503    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20504        &self.inlay_hint_cache
20505    }
20506
20507    pub fn replay_insert_event(
20508        &mut self,
20509        text: &str,
20510        relative_utf16_range: Option<Range<isize>>,
20511        window: &mut Window,
20512        cx: &mut Context<Self>,
20513    ) {
20514        if !self.input_enabled {
20515            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20516            return;
20517        }
20518        if let Some(relative_utf16_range) = relative_utf16_range {
20519            let selections = self.selections.all::<OffsetUtf16>(cx);
20520            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20521                let new_ranges = selections.into_iter().map(|range| {
20522                    let start = OffsetUtf16(
20523                        range
20524                            .head()
20525                            .0
20526                            .saturating_add_signed(relative_utf16_range.start),
20527                    );
20528                    let end = OffsetUtf16(
20529                        range
20530                            .head()
20531                            .0
20532                            .saturating_add_signed(relative_utf16_range.end),
20533                    );
20534                    start..end
20535                });
20536                s.select_ranges(new_ranges);
20537            });
20538        }
20539
20540        self.handle_input(text, window, cx);
20541    }
20542
20543    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20544        let Some(provider) = self.semantics_provider.as_ref() else {
20545            return false;
20546        };
20547
20548        let mut supports = false;
20549        self.buffer().update(cx, |this, cx| {
20550            this.for_each_buffer(|buffer| {
20551                supports |= provider.supports_inlay_hints(buffer, cx);
20552            });
20553        });
20554
20555        supports
20556    }
20557
20558    pub fn is_focused(&self, window: &Window) -> bool {
20559        self.focus_handle.is_focused(window)
20560    }
20561
20562    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20563        cx.emit(EditorEvent::Focused);
20564
20565        if let Some(descendant) = self
20566            .last_focused_descendant
20567            .take()
20568            .and_then(|descendant| descendant.upgrade())
20569        {
20570            window.focus(&descendant);
20571        } else {
20572            if let Some(blame) = self.blame.as_ref() {
20573                blame.update(cx, GitBlame::focus)
20574            }
20575
20576            self.blink_manager.update(cx, BlinkManager::enable);
20577            self.show_cursor_names(window, cx);
20578            self.buffer.update(cx, |buffer, cx| {
20579                buffer.finalize_last_transaction(cx);
20580                if self.leader_id.is_none() {
20581                    buffer.set_active_selections(
20582                        &self.selections.disjoint_anchors(),
20583                        self.selections.line_mode,
20584                        self.cursor_shape,
20585                        cx,
20586                    );
20587                }
20588            });
20589        }
20590    }
20591
20592    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20593        cx.emit(EditorEvent::FocusedIn)
20594    }
20595
20596    fn handle_focus_out(
20597        &mut self,
20598        event: FocusOutEvent,
20599        _window: &mut Window,
20600        cx: &mut Context<Self>,
20601    ) {
20602        if event.blurred != self.focus_handle {
20603            self.last_focused_descendant = Some(event.blurred);
20604        }
20605        self.selection_drag_state = SelectionDragState::None;
20606        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20607    }
20608
20609    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20610        self.blink_manager.update(cx, BlinkManager::disable);
20611        self.buffer
20612            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20613
20614        if let Some(blame) = self.blame.as_ref() {
20615            blame.update(cx, GitBlame::blur)
20616        }
20617        if !self.hover_state.focused(window, cx) {
20618            hide_hover(self, cx);
20619        }
20620        if !self
20621            .context_menu
20622            .borrow()
20623            .as_ref()
20624            .is_some_and(|context_menu| context_menu.focused(window, cx))
20625        {
20626            self.hide_context_menu(window, cx);
20627        }
20628        self.discard_inline_completion(false, cx);
20629        cx.emit(EditorEvent::Blurred);
20630        cx.notify();
20631    }
20632
20633    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20634        let mut pending: String = window
20635            .pending_input_keystrokes()
20636            .into_iter()
20637            .flatten()
20638            .filter_map(|keystroke| {
20639                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20640                    keystroke.key_char.clone()
20641                } else {
20642                    None
20643                }
20644            })
20645            .collect();
20646
20647        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20648            pending = "".to_string();
20649        }
20650
20651        let existing_pending = self
20652            .text_highlights::<PendingInput>(cx)
20653            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20654        if existing_pending.is_none() && pending.is_empty() {
20655            return;
20656        }
20657        let transaction =
20658            self.transact(window, cx, |this, window, cx| {
20659                let selections = this.selections.all::<usize>(cx);
20660                let edits = selections
20661                    .iter()
20662                    .map(|selection| (selection.end..selection.end, pending.clone()));
20663                this.edit(edits, cx);
20664                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20665                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20666                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20667                    }));
20668                });
20669                if let Some(existing_ranges) = existing_pending {
20670                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20671                    this.edit(edits, cx);
20672                }
20673            });
20674
20675        let snapshot = self.snapshot(window, cx);
20676        let ranges = self
20677            .selections
20678            .all::<usize>(cx)
20679            .into_iter()
20680            .map(|selection| {
20681                snapshot.buffer_snapshot.anchor_after(selection.end)
20682                    ..snapshot
20683                        .buffer_snapshot
20684                        .anchor_before(selection.end + pending.len())
20685            })
20686            .collect();
20687
20688        if pending.is_empty() {
20689            self.clear_highlights::<PendingInput>(cx);
20690        } else {
20691            self.highlight_text::<PendingInput>(
20692                ranges,
20693                HighlightStyle {
20694                    underline: Some(UnderlineStyle {
20695                        thickness: px(1.),
20696                        color: None,
20697                        wavy: false,
20698                    }),
20699                    ..Default::default()
20700                },
20701                cx,
20702            );
20703        }
20704
20705        self.ime_transaction = self.ime_transaction.or(transaction);
20706        if let Some(transaction) = self.ime_transaction {
20707            self.buffer.update(cx, |buffer, cx| {
20708                buffer.group_until_transaction(transaction, cx);
20709            });
20710        }
20711
20712        if self.text_highlights::<PendingInput>(cx).is_none() {
20713            self.ime_transaction.take();
20714        }
20715    }
20716
20717    pub fn register_action_renderer(
20718        &mut self,
20719        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20720    ) -> Subscription {
20721        let id = self.next_editor_action_id.post_inc();
20722        self.editor_actions
20723            .borrow_mut()
20724            .insert(id, Box::new(listener));
20725
20726        let editor_actions = self.editor_actions.clone();
20727        Subscription::new(move || {
20728            editor_actions.borrow_mut().remove(&id);
20729        })
20730    }
20731
20732    pub fn register_action<A: Action>(
20733        &mut self,
20734        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20735    ) -> Subscription {
20736        let id = self.next_editor_action_id.post_inc();
20737        let listener = Arc::new(listener);
20738        self.editor_actions.borrow_mut().insert(
20739            id,
20740            Box::new(move |_, window, _| {
20741                let listener = listener.clone();
20742                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20743                    let action = action.downcast_ref().unwrap();
20744                    if phase == DispatchPhase::Bubble {
20745                        listener(action, window, cx)
20746                    }
20747                })
20748            }),
20749        );
20750
20751        let editor_actions = self.editor_actions.clone();
20752        Subscription::new(move || {
20753            editor_actions.borrow_mut().remove(&id);
20754        })
20755    }
20756
20757    pub fn file_header_size(&self) -> u32 {
20758        FILE_HEADER_HEIGHT
20759    }
20760
20761    pub fn restore(
20762        &mut self,
20763        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20764        window: &mut Window,
20765        cx: &mut Context<Self>,
20766    ) {
20767        let workspace = self.workspace();
20768        let project = self.project.as_ref();
20769        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20770            let mut tasks = Vec::new();
20771            for (buffer_id, changes) in revert_changes {
20772                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20773                    buffer.update(cx, |buffer, cx| {
20774                        buffer.edit(
20775                            changes
20776                                .into_iter()
20777                                .map(|(range, text)| (range, text.to_string())),
20778                            None,
20779                            cx,
20780                        );
20781                    });
20782
20783                    if let Some(project) =
20784                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20785                    {
20786                        project.update(cx, |project, cx| {
20787                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20788                        })
20789                    }
20790                }
20791            }
20792            tasks
20793        });
20794        cx.spawn_in(window, async move |_, cx| {
20795            for (buffer, task) in save_tasks {
20796                let result = task.await;
20797                if result.is_err() {
20798                    let Some(path) = buffer
20799                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20800                        .ok()
20801                    else {
20802                        continue;
20803                    };
20804                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20805                        let Some(task) = cx
20806                            .update_window_entity(&workspace, |workspace, window, cx| {
20807                                workspace
20808                                    .open_path_preview(path, None, false, false, false, window, cx)
20809                            })
20810                            .ok()
20811                        else {
20812                            continue;
20813                        };
20814                        task.await.log_err();
20815                    }
20816                }
20817            }
20818        })
20819        .detach();
20820        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20821            selections.refresh()
20822        });
20823    }
20824
20825    pub fn to_pixel_point(
20826        &self,
20827        source: multi_buffer::Anchor,
20828        editor_snapshot: &EditorSnapshot,
20829        window: &mut Window,
20830    ) -> Option<gpui::Point<Pixels>> {
20831        let source_point = source.to_display_point(editor_snapshot);
20832        self.display_to_pixel_point(source_point, editor_snapshot, window)
20833    }
20834
20835    pub fn display_to_pixel_point(
20836        &self,
20837        source: DisplayPoint,
20838        editor_snapshot: &EditorSnapshot,
20839        window: &mut Window,
20840    ) -> Option<gpui::Point<Pixels>> {
20841        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20842        let text_layout_details = self.text_layout_details(window);
20843        let scroll_top = text_layout_details
20844            .scroll_anchor
20845            .scroll_position(editor_snapshot)
20846            .y;
20847
20848        if source.row().as_f32() < scroll_top.floor() {
20849            return None;
20850        }
20851        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20852        let source_y = line_height * (source.row().as_f32() - scroll_top);
20853        Some(gpui::Point::new(source_x, source_y))
20854    }
20855
20856    pub fn has_visible_completions_menu(&self) -> bool {
20857        !self.edit_prediction_preview_is_active()
20858            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20859                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20860            })
20861    }
20862
20863    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20864        if self.mode.is_minimap() {
20865            return;
20866        }
20867        self.addons
20868            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20869    }
20870
20871    pub fn unregister_addon<T: Addon>(&mut self) {
20872        self.addons.remove(&std::any::TypeId::of::<T>());
20873    }
20874
20875    pub fn addon<T: Addon>(&self) -> Option<&T> {
20876        let type_id = std::any::TypeId::of::<T>();
20877        self.addons
20878            .get(&type_id)
20879            .and_then(|item| item.to_any().downcast_ref::<T>())
20880    }
20881
20882    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20883        let type_id = std::any::TypeId::of::<T>();
20884        self.addons
20885            .get_mut(&type_id)
20886            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20887    }
20888
20889    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20890        let text_layout_details = self.text_layout_details(window);
20891        let style = &text_layout_details.editor_style;
20892        let font_id = window.text_system().resolve_font(&style.text.font());
20893        let font_size = style.text.font_size.to_pixels(window.rem_size());
20894        let line_height = style.text.line_height_in_pixels(window.rem_size());
20895        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20896        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20897
20898        CharacterDimensions {
20899            em_width,
20900            em_advance,
20901            line_height,
20902        }
20903    }
20904
20905    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20906        self.load_diff_task.clone()
20907    }
20908
20909    fn read_metadata_from_db(
20910        &mut self,
20911        item_id: u64,
20912        workspace_id: WorkspaceId,
20913        window: &mut Window,
20914        cx: &mut Context<Editor>,
20915    ) {
20916        if self.is_singleton(cx)
20917            && !self.mode.is_minimap()
20918            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20919        {
20920            let buffer_snapshot = OnceCell::new();
20921
20922            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20923                if !folds.is_empty() {
20924                    let snapshot =
20925                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20926                    self.fold_ranges(
20927                        folds
20928                            .into_iter()
20929                            .map(|(start, end)| {
20930                                snapshot.clip_offset(start, Bias::Left)
20931                                    ..snapshot.clip_offset(end, Bias::Right)
20932                            })
20933                            .collect(),
20934                        false,
20935                        window,
20936                        cx,
20937                    );
20938                }
20939            }
20940
20941            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20942                if !selections.is_empty() {
20943                    let snapshot =
20944                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20945                    // skip adding the initial selection to selection history
20946                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20947                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20948                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20949                            snapshot.clip_offset(start, Bias::Left)
20950                                ..snapshot.clip_offset(end, Bias::Right)
20951                        }));
20952                    });
20953                    self.selection_history.mode = SelectionHistoryMode::Normal;
20954                }
20955            };
20956        }
20957
20958        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20959    }
20960
20961    fn update_lsp_data(
20962        &mut self,
20963        ignore_cache: bool,
20964        for_buffer: Option<BufferId>,
20965        window: &mut Window,
20966        cx: &mut Context<'_, Self>,
20967    ) {
20968        self.pull_diagnostics(for_buffer, window, cx);
20969        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20970    }
20971}
20972
20973fn vim_enabled(cx: &App) -> bool {
20974    cx.global::<SettingsStore>()
20975        .raw_user_settings()
20976        .get("vim_mode")
20977        == Some(&serde_json::Value::Bool(true))
20978}
20979
20980fn process_completion_for_edit(
20981    completion: &Completion,
20982    intent: CompletionIntent,
20983    buffer: &Entity<Buffer>,
20984    cursor_position: &text::Anchor,
20985    cx: &mut Context<Editor>,
20986) -> CompletionEdit {
20987    let buffer = buffer.read(cx);
20988    let buffer_snapshot = buffer.snapshot();
20989    let (snippet, new_text) = if completion.is_snippet() {
20990        // Workaround for typescript language server issues so that methods don't expand within
20991        // strings and functions with type expressions. The previous point is used because the query
20992        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20993        let mut snippet_source = completion.new_text.clone();
20994        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20995        previous_point.column = previous_point.column.saturating_sub(1);
20996        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20997            if scope.prefers_label_for_snippet_in_completion() {
20998                if let Some(label) = completion.label() {
20999                    if matches!(
21000                        completion.kind(),
21001                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21002                    ) {
21003                        snippet_source = label;
21004                    }
21005                }
21006            }
21007        }
21008        match Snippet::parse(&snippet_source).log_err() {
21009            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21010            None => (None, completion.new_text.clone()),
21011        }
21012    } else {
21013        (None, completion.new_text.clone())
21014    };
21015
21016    let mut range_to_replace = {
21017        let replace_range = &completion.replace_range;
21018        if let CompletionSource::Lsp {
21019            insert_range: Some(insert_range),
21020            ..
21021        } = &completion.source
21022        {
21023            debug_assert_eq!(
21024                insert_range.start, replace_range.start,
21025                "insert_range and replace_range should start at the same position"
21026            );
21027            debug_assert!(
21028                insert_range
21029                    .start
21030                    .cmp(&cursor_position, &buffer_snapshot)
21031                    .is_le(),
21032                "insert_range should start before or at cursor position"
21033            );
21034            debug_assert!(
21035                replace_range
21036                    .start
21037                    .cmp(&cursor_position, &buffer_snapshot)
21038                    .is_le(),
21039                "replace_range should start before or at cursor position"
21040            );
21041            debug_assert!(
21042                insert_range
21043                    .end
21044                    .cmp(&cursor_position, &buffer_snapshot)
21045                    .is_le(),
21046                "insert_range should end before or at cursor position"
21047            );
21048
21049            let should_replace = match intent {
21050                CompletionIntent::CompleteWithInsert => false,
21051                CompletionIntent::CompleteWithReplace => true,
21052                CompletionIntent::Complete | CompletionIntent::Compose => {
21053                    let insert_mode =
21054                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21055                            .completions
21056                            .lsp_insert_mode;
21057                    match insert_mode {
21058                        LspInsertMode::Insert => false,
21059                        LspInsertMode::Replace => true,
21060                        LspInsertMode::ReplaceSubsequence => {
21061                            let mut text_to_replace = buffer.chars_for_range(
21062                                buffer.anchor_before(replace_range.start)
21063                                    ..buffer.anchor_after(replace_range.end),
21064                            );
21065                            let mut current_needle = text_to_replace.next();
21066                            for haystack_ch in completion.label.text.chars() {
21067                                if let Some(needle_ch) = current_needle {
21068                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21069                                        current_needle = text_to_replace.next();
21070                                    }
21071                                }
21072                            }
21073                            current_needle.is_none()
21074                        }
21075                        LspInsertMode::ReplaceSuffix => {
21076                            if replace_range
21077                                .end
21078                                .cmp(&cursor_position, &buffer_snapshot)
21079                                .is_gt()
21080                            {
21081                                let range_after_cursor = *cursor_position..replace_range.end;
21082                                let text_after_cursor = buffer
21083                                    .text_for_range(
21084                                        buffer.anchor_before(range_after_cursor.start)
21085                                            ..buffer.anchor_after(range_after_cursor.end),
21086                                    )
21087                                    .collect::<String>()
21088                                    .to_ascii_lowercase();
21089                                completion
21090                                    .label
21091                                    .text
21092                                    .to_ascii_lowercase()
21093                                    .ends_with(&text_after_cursor)
21094                            } else {
21095                                true
21096                            }
21097                        }
21098                    }
21099                }
21100            };
21101
21102            if should_replace {
21103                replace_range.clone()
21104            } else {
21105                insert_range.clone()
21106            }
21107        } else {
21108            replace_range.clone()
21109        }
21110    };
21111
21112    if range_to_replace
21113        .end
21114        .cmp(&cursor_position, &buffer_snapshot)
21115        .is_lt()
21116    {
21117        range_to_replace.end = *cursor_position;
21118    }
21119
21120    CompletionEdit {
21121        new_text,
21122        replace_range: range_to_replace.to_offset(&buffer),
21123        snippet,
21124    }
21125}
21126
21127struct CompletionEdit {
21128    new_text: String,
21129    replace_range: Range<usize>,
21130    snippet: Option<Snippet>,
21131}
21132
21133fn insert_extra_newline_brackets(
21134    buffer: &MultiBufferSnapshot,
21135    range: Range<usize>,
21136    language: &language::LanguageScope,
21137) -> bool {
21138    let leading_whitespace_len = buffer
21139        .reversed_chars_at(range.start)
21140        .take_while(|c| c.is_whitespace() && *c != '\n')
21141        .map(|c| c.len_utf8())
21142        .sum::<usize>();
21143    let trailing_whitespace_len = buffer
21144        .chars_at(range.end)
21145        .take_while(|c| c.is_whitespace() && *c != '\n')
21146        .map(|c| c.len_utf8())
21147        .sum::<usize>();
21148    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21149
21150    language.brackets().any(|(pair, enabled)| {
21151        let pair_start = pair.start.trim_end();
21152        let pair_end = pair.end.trim_start();
21153
21154        enabled
21155            && pair.newline
21156            && buffer.contains_str_at(range.end, pair_end)
21157            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21158    })
21159}
21160
21161fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21162    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21163        [(buffer, range, _)] => (*buffer, range.clone()),
21164        _ => return false,
21165    };
21166    let pair = {
21167        let mut result: Option<BracketMatch> = None;
21168
21169        for pair in buffer
21170            .all_bracket_ranges(range.clone())
21171            .filter(move |pair| {
21172                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21173            })
21174        {
21175            let len = pair.close_range.end - pair.open_range.start;
21176
21177            if let Some(existing) = &result {
21178                let existing_len = existing.close_range.end - existing.open_range.start;
21179                if len > existing_len {
21180                    continue;
21181                }
21182            }
21183
21184            result = Some(pair);
21185        }
21186
21187        result
21188    };
21189    let Some(pair) = pair else {
21190        return false;
21191    };
21192    pair.newline_only
21193        && buffer
21194            .chars_for_range(pair.open_range.end..range.start)
21195            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21196            .all(|c| c.is_whitespace() && c != '\n')
21197}
21198
21199fn update_uncommitted_diff_for_buffer(
21200    editor: Entity<Editor>,
21201    project: &Entity<Project>,
21202    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21203    buffer: Entity<MultiBuffer>,
21204    cx: &mut App,
21205) -> Task<()> {
21206    let mut tasks = Vec::new();
21207    project.update(cx, |project, cx| {
21208        for buffer in buffers {
21209            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21210                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21211            }
21212        }
21213    });
21214    cx.spawn(async move |cx| {
21215        let diffs = future::join_all(tasks).await;
21216        if editor
21217            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21218            .unwrap_or(false)
21219        {
21220            return;
21221        }
21222
21223        buffer
21224            .update(cx, |buffer, cx| {
21225                for diff in diffs.into_iter().flatten() {
21226                    buffer.add_diff(diff, cx);
21227                }
21228            })
21229            .ok();
21230    })
21231}
21232
21233fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21234    let tab_size = tab_size.get() as usize;
21235    let mut width = offset;
21236
21237    for ch in text.chars() {
21238        width += if ch == '\t' {
21239            tab_size - (width % tab_size)
21240        } else {
21241            1
21242        };
21243    }
21244
21245    width - offset
21246}
21247
21248#[cfg(test)]
21249mod tests {
21250    use super::*;
21251
21252    #[test]
21253    fn test_string_size_with_expanded_tabs() {
21254        let nz = |val| NonZeroU32::new(val).unwrap();
21255        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21256        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21257        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21258        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21259        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21260        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21261        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21262        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21263    }
21264}
21265
21266/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21267struct WordBreakingTokenizer<'a> {
21268    input: &'a str,
21269}
21270
21271impl<'a> WordBreakingTokenizer<'a> {
21272    fn new(input: &'a str) -> Self {
21273        Self { input }
21274    }
21275}
21276
21277fn is_char_ideographic(ch: char) -> bool {
21278    use unicode_script::Script::*;
21279    use unicode_script::UnicodeScript;
21280    matches!(ch.script(), Han | Tangut | Yi)
21281}
21282
21283fn is_grapheme_ideographic(text: &str) -> bool {
21284    text.chars().any(is_char_ideographic)
21285}
21286
21287fn is_grapheme_whitespace(text: &str) -> bool {
21288    text.chars().any(|x| x.is_whitespace())
21289}
21290
21291fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21292    text.chars().next().map_or(false, |ch| {
21293        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21294    })
21295}
21296
21297#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21298enum WordBreakToken<'a> {
21299    Word { token: &'a str, grapheme_len: usize },
21300    InlineWhitespace { token: &'a str, grapheme_len: usize },
21301    Newline,
21302}
21303
21304impl<'a> Iterator for WordBreakingTokenizer<'a> {
21305    /// Yields a span, the count of graphemes in the token, and whether it was
21306    /// whitespace. Note that it also breaks at word boundaries.
21307    type Item = WordBreakToken<'a>;
21308
21309    fn next(&mut self) -> Option<Self::Item> {
21310        use unicode_segmentation::UnicodeSegmentation;
21311        if self.input.is_empty() {
21312            return None;
21313        }
21314
21315        let mut iter = self.input.graphemes(true).peekable();
21316        let mut offset = 0;
21317        let mut grapheme_len = 0;
21318        if let Some(first_grapheme) = iter.next() {
21319            let is_newline = first_grapheme == "\n";
21320            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21321            offset += first_grapheme.len();
21322            grapheme_len += 1;
21323            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21324                if let Some(grapheme) = iter.peek().copied() {
21325                    if should_stay_with_preceding_ideograph(grapheme) {
21326                        offset += grapheme.len();
21327                        grapheme_len += 1;
21328                    }
21329                }
21330            } else {
21331                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21332                let mut next_word_bound = words.peek().copied();
21333                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21334                    next_word_bound = words.next();
21335                }
21336                while let Some(grapheme) = iter.peek().copied() {
21337                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21338                        break;
21339                    };
21340                    if is_grapheme_whitespace(grapheme) != is_whitespace
21341                        || (grapheme == "\n") != is_newline
21342                    {
21343                        break;
21344                    };
21345                    offset += grapheme.len();
21346                    grapheme_len += 1;
21347                    iter.next();
21348                }
21349            }
21350            let token = &self.input[..offset];
21351            self.input = &self.input[offset..];
21352            if token == "\n" {
21353                Some(WordBreakToken::Newline)
21354            } else if is_whitespace {
21355                Some(WordBreakToken::InlineWhitespace {
21356                    token,
21357                    grapheme_len,
21358                })
21359            } else {
21360                Some(WordBreakToken::Word {
21361                    token,
21362                    grapheme_len,
21363                })
21364            }
21365        } else {
21366            None
21367        }
21368    }
21369}
21370
21371#[test]
21372fn test_word_breaking_tokenizer() {
21373    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21374        ("", &[]),
21375        ("  ", &[whitespace("  ", 2)]),
21376        ("Ʒ", &[word("Ʒ", 1)]),
21377        ("Ǽ", &[word("Ǽ", 1)]),
21378        ("", &[word("", 1)]),
21379        ("⋑⋑", &[word("⋑⋑", 2)]),
21380        (
21381            "原理,进而",
21382            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21383        ),
21384        (
21385            "hello world",
21386            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21387        ),
21388        (
21389            "hello, world",
21390            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21391        ),
21392        (
21393            "  hello world",
21394            &[
21395                whitespace("  ", 2),
21396                word("hello", 5),
21397                whitespace(" ", 1),
21398                word("world", 5),
21399            ],
21400        ),
21401        (
21402            "这是什么 \n 钢笔",
21403            &[
21404                word("", 1),
21405                word("", 1),
21406                word("", 1),
21407                word("", 1),
21408                whitespace(" ", 1),
21409                newline(),
21410                whitespace(" ", 1),
21411                word("", 1),
21412                word("", 1),
21413            ],
21414        ),
21415        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21416    ];
21417
21418    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21419        WordBreakToken::Word {
21420            token,
21421            grapheme_len,
21422        }
21423    }
21424
21425    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21426        WordBreakToken::InlineWhitespace {
21427            token,
21428            grapheme_len,
21429        }
21430    }
21431
21432    fn newline() -> WordBreakToken<'static> {
21433        WordBreakToken::Newline
21434    }
21435
21436    for (input, result) in tests {
21437        assert_eq!(
21438            WordBreakingTokenizer::new(input)
21439                .collect::<Vec<_>>()
21440                .as_slice(),
21441            *result,
21442        );
21443    }
21444}
21445
21446fn wrap_with_prefix(
21447    first_line_prefix: String,
21448    subsequent_lines_prefix: String,
21449    unwrapped_text: String,
21450    wrap_column: usize,
21451    tab_size: NonZeroU32,
21452    preserve_existing_whitespace: bool,
21453) -> String {
21454    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21455    let subsequent_lines_prefix_len =
21456        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21457    let mut wrapped_text = String::new();
21458    let mut current_line = first_line_prefix.clone();
21459    let mut is_first_line = true;
21460
21461    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21462    let mut current_line_len = first_line_prefix_len;
21463    let mut in_whitespace = false;
21464    for token in tokenizer {
21465        let have_preceding_whitespace = in_whitespace;
21466        match token {
21467            WordBreakToken::Word {
21468                token,
21469                grapheme_len,
21470            } => {
21471                in_whitespace = false;
21472                let current_prefix_len = if is_first_line {
21473                    first_line_prefix_len
21474                } else {
21475                    subsequent_lines_prefix_len
21476                };
21477                if current_line_len + grapheme_len > wrap_column
21478                    && current_line_len != current_prefix_len
21479                {
21480                    wrapped_text.push_str(current_line.trim_end());
21481                    wrapped_text.push('\n');
21482                    is_first_line = false;
21483                    current_line = subsequent_lines_prefix.clone();
21484                    current_line_len = subsequent_lines_prefix_len;
21485                }
21486                current_line.push_str(token);
21487                current_line_len += grapheme_len;
21488            }
21489            WordBreakToken::InlineWhitespace {
21490                mut token,
21491                mut grapheme_len,
21492            } => {
21493                in_whitespace = true;
21494                if have_preceding_whitespace && !preserve_existing_whitespace {
21495                    continue;
21496                }
21497                if !preserve_existing_whitespace {
21498                    token = " ";
21499                    grapheme_len = 1;
21500                }
21501                let current_prefix_len = if is_first_line {
21502                    first_line_prefix_len
21503                } else {
21504                    subsequent_lines_prefix_len
21505                };
21506                if current_line_len + grapheme_len > wrap_column {
21507                    wrapped_text.push_str(current_line.trim_end());
21508                    wrapped_text.push('\n');
21509                    is_first_line = false;
21510                    current_line = subsequent_lines_prefix.clone();
21511                    current_line_len = subsequent_lines_prefix_len;
21512                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21513                    current_line.push_str(token);
21514                    current_line_len += grapheme_len;
21515                }
21516            }
21517            WordBreakToken::Newline => {
21518                in_whitespace = true;
21519                let current_prefix_len = if is_first_line {
21520                    first_line_prefix_len
21521                } else {
21522                    subsequent_lines_prefix_len
21523                };
21524                if preserve_existing_whitespace {
21525                    wrapped_text.push_str(current_line.trim_end());
21526                    wrapped_text.push('\n');
21527                    is_first_line = false;
21528                    current_line = subsequent_lines_prefix.clone();
21529                    current_line_len = subsequent_lines_prefix_len;
21530                } else if have_preceding_whitespace {
21531                    continue;
21532                } else if current_line_len + 1 > wrap_column
21533                    && current_line_len != current_prefix_len
21534                {
21535                    wrapped_text.push_str(current_line.trim_end());
21536                    wrapped_text.push('\n');
21537                    is_first_line = false;
21538                    current_line = subsequent_lines_prefix.clone();
21539                    current_line_len = subsequent_lines_prefix_len;
21540                } else if current_line_len != current_prefix_len {
21541                    current_line.push(' ');
21542                    current_line_len += 1;
21543                }
21544            }
21545        }
21546    }
21547
21548    if !current_line.is_empty() {
21549        wrapped_text.push_str(&current_line);
21550    }
21551    wrapped_text
21552}
21553
21554#[test]
21555fn test_wrap_with_prefix() {
21556    assert_eq!(
21557        wrap_with_prefix(
21558            "# ".to_string(),
21559            "# ".to_string(),
21560            "abcdefg".to_string(),
21561            4,
21562            NonZeroU32::new(4).unwrap(),
21563            false,
21564        ),
21565        "# abcdefg"
21566    );
21567    assert_eq!(
21568        wrap_with_prefix(
21569            "".to_string(),
21570            "".to_string(),
21571            "\thello world".to_string(),
21572            8,
21573            NonZeroU32::new(4).unwrap(),
21574            false,
21575        ),
21576        "hello\nworld"
21577    );
21578    assert_eq!(
21579        wrap_with_prefix(
21580            "// ".to_string(),
21581            "// ".to_string(),
21582            "xx \nyy zz aa bb cc".to_string(),
21583            12,
21584            NonZeroU32::new(4).unwrap(),
21585            false,
21586        ),
21587        "// xx yy zz\n// aa bb cc"
21588    );
21589    assert_eq!(
21590        wrap_with_prefix(
21591            String::new(),
21592            String::new(),
21593            "这是什么 \n 钢笔".to_string(),
21594            3,
21595            NonZeroU32::new(4).unwrap(),
21596            false,
21597        ),
21598        "这是什\n么 钢\n"
21599    );
21600}
21601
21602pub trait CollaborationHub {
21603    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21604    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21605    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21606}
21607
21608impl CollaborationHub for Entity<Project> {
21609    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21610        self.read(cx).collaborators()
21611    }
21612
21613    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21614        self.read(cx).user_store().read(cx).participant_indices()
21615    }
21616
21617    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21618        let this = self.read(cx);
21619        let user_ids = this.collaborators().values().map(|c| c.user_id);
21620        this.user_store().read(cx).participant_names(user_ids, cx)
21621    }
21622}
21623
21624pub trait SemanticsProvider {
21625    fn hover(
21626        &self,
21627        buffer: &Entity<Buffer>,
21628        position: text::Anchor,
21629        cx: &mut App,
21630    ) -> Option<Task<Vec<project::Hover>>>;
21631
21632    fn inline_values(
21633        &self,
21634        buffer_handle: Entity<Buffer>,
21635        range: Range<text::Anchor>,
21636        cx: &mut App,
21637    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21638
21639    fn inlay_hints(
21640        &self,
21641        buffer_handle: Entity<Buffer>,
21642        range: Range<text::Anchor>,
21643        cx: &mut App,
21644    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21645
21646    fn resolve_inlay_hint(
21647        &self,
21648        hint: InlayHint,
21649        buffer_handle: Entity<Buffer>,
21650        server_id: LanguageServerId,
21651        cx: &mut App,
21652    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21653
21654    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21655
21656    fn document_highlights(
21657        &self,
21658        buffer: &Entity<Buffer>,
21659        position: text::Anchor,
21660        cx: &mut App,
21661    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21662
21663    fn definitions(
21664        &self,
21665        buffer: &Entity<Buffer>,
21666        position: text::Anchor,
21667        kind: GotoDefinitionKind,
21668        cx: &mut App,
21669    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21670
21671    fn range_for_rename(
21672        &self,
21673        buffer: &Entity<Buffer>,
21674        position: text::Anchor,
21675        cx: &mut App,
21676    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21677
21678    fn perform_rename(
21679        &self,
21680        buffer: &Entity<Buffer>,
21681        position: text::Anchor,
21682        new_name: String,
21683        cx: &mut App,
21684    ) -> Option<Task<Result<ProjectTransaction>>>;
21685}
21686
21687pub trait CompletionProvider {
21688    fn completions(
21689        &self,
21690        excerpt_id: ExcerptId,
21691        buffer: &Entity<Buffer>,
21692        buffer_position: text::Anchor,
21693        trigger: CompletionContext,
21694        window: &mut Window,
21695        cx: &mut Context<Editor>,
21696    ) -> Task<Result<Vec<CompletionResponse>>>;
21697
21698    fn resolve_completions(
21699        &self,
21700        _buffer: Entity<Buffer>,
21701        _completion_indices: Vec<usize>,
21702        _completions: Rc<RefCell<Box<[Completion]>>>,
21703        _cx: &mut Context<Editor>,
21704    ) -> Task<Result<bool>> {
21705        Task::ready(Ok(false))
21706    }
21707
21708    fn apply_additional_edits_for_completion(
21709        &self,
21710        _buffer: Entity<Buffer>,
21711        _completions: Rc<RefCell<Box<[Completion]>>>,
21712        _completion_index: usize,
21713        _push_to_history: bool,
21714        _cx: &mut Context<Editor>,
21715    ) -> Task<Result<Option<language::Transaction>>> {
21716        Task::ready(Ok(None))
21717    }
21718
21719    fn is_completion_trigger(
21720        &self,
21721        buffer: &Entity<Buffer>,
21722        position: language::Anchor,
21723        text: &str,
21724        trigger_in_words: bool,
21725        menu_is_open: bool,
21726        cx: &mut Context<Editor>,
21727    ) -> bool;
21728
21729    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21730
21731    fn sort_completions(&self) -> bool {
21732        true
21733    }
21734
21735    fn filter_completions(&self) -> bool {
21736        true
21737    }
21738}
21739
21740pub trait CodeActionProvider {
21741    fn id(&self) -> Arc<str>;
21742
21743    fn code_actions(
21744        &self,
21745        buffer: &Entity<Buffer>,
21746        range: Range<text::Anchor>,
21747        window: &mut Window,
21748        cx: &mut App,
21749    ) -> Task<Result<Vec<CodeAction>>>;
21750
21751    fn apply_code_action(
21752        &self,
21753        buffer_handle: Entity<Buffer>,
21754        action: CodeAction,
21755        excerpt_id: ExcerptId,
21756        push_to_history: bool,
21757        window: &mut Window,
21758        cx: &mut App,
21759    ) -> Task<Result<ProjectTransaction>>;
21760}
21761
21762impl CodeActionProvider for Entity<Project> {
21763    fn id(&self) -> Arc<str> {
21764        "project".into()
21765    }
21766
21767    fn code_actions(
21768        &self,
21769        buffer: &Entity<Buffer>,
21770        range: Range<text::Anchor>,
21771        _window: &mut Window,
21772        cx: &mut App,
21773    ) -> Task<Result<Vec<CodeAction>>> {
21774        self.update(cx, |project, cx| {
21775            let code_lens = project.code_lens(buffer, range.clone(), cx);
21776            let code_actions = project.code_actions(buffer, range, None, cx);
21777            cx.background_spawn(async move {
21778                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21779                Ok(code_lens
21780                    .context("code lens fetch")?
21781                    .into_iter()
21782                    .chain(code_actions.context("code action fetch")?)
21783                    .collect())
21784            })
21785        })
21786    }
21787
21788    fn apply_code_action(
21789        &self,
21790        buffer_handle: Entity<Buffer>,
21791        action: CodeAction,
21792        _excerpt_id: ExcerptId,
21793        push_to_history: bool,
21794        _window: &mut Window,
21795        cx: &mut App,
21796    ) -> Task<Result<ProjectTransaction>> {
21797        self.update(cx, |project, cx| {
21798            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21799        })
21800    }
21801}
21802
21803fn snippet_completions(
21804    project: &Project,
21805    buffer: &Entity<Buffer>,
21806    buffer_position: text::Anchor,
21807    cx: &mut App,
21808) -> Task<Result<CompletionResponse>> {
21809    let languages = buffer.read(cx).languages_at(buffer_position);
21810    let snippet_store = project.snippets().read(cx);
21811
21812    let scopes: Vec<_> = languages
21813        .iter()
21814        .filter_map(|language| {
21815            let language_name = language.lsp_id();
21816            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21817
21818            if snippets.is_empty() {
21819                None
21820            } else {
21821                Some((language.default_scope(), snippets))
21822            }
21823        })
21824        .collect();
21825
21826    if scopes.is_empty() {
21827        return Task::ready(Ok(CompletionResponse {
21828            completions: vec![],
21829            is_incomplete: false,
21830        }));
21831    }
21832
21833    let snapshot = buffer.read(cx).text_snapshot();
21834    let chars: String = snapshot
21835        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21836        .collect();
21837    let executor = cx.background_executor().clone();
21838
21839    cx.background_spawn(async move {
21840        let mut is_incomplete = false;
21841        let mut completions: Vec<Completion> = Vec::new();
21842        for (scope, snippets) in scopes.into_iter() {
21843            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21844            let mut last_word = chars
21845                .chars()
21846                .take_while(|c| classifier.is_word(*c))
21847                .collect::<String>();
21848            last_word = last_word.chars().rev().collect();
21849
21850            if last_word.is_empty() {
21851                return Ok(CompletionResponse {
21852                    completions: vec![],
21853                    is_incomplete: true,
21854                });
21855            }
21856
21857            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21858            let to_lsp = |point: &text::Anchor| {
21859                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21860                point_to_lsp(end)
21861            };
21862            let lsp_end = to_lsp(&buffer_position);
21863
21864            let candidates = snippets
21865                .iter()
21866                .enumerate()
21867                .flat_map(|(ix, snippet)| {
21868                    snippet
21869                        .prefix
21870                        .iter()
21871                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21872                })
21873                .collect::<Vec<StringMatchCandidate>>();
21874
21875            const MAX_RESULTS: usize = 100;
21876            let mut matches = fuzzy::match_strings(
21877                &candidates,
21878                &last_word,
21879                last_word.chars().any(|c| c.is_uppercase()),
21880                true,
21881                MAX_RESULTS,
21882                &Default::default(),
21883                executor.clone(),
21884            )
21885            .await;
21886
21887            if matches.len() >= MAX_RESULTS {
21888                is_incomplete = true;
21889            }
21890
21891            // Remove all candidates where the query's start does not match the start of any word in the candidate
21892            if let Some(query_start) = last_word.chars().next() {
21893                matches.retain(|string_match| {
21894                    split_words(&string_match.string).any(|word| {
21895                        // Check that the first codepoint of the word as lowercase matches the first
21896                        // codepoint of the query as lowercase
21897                        word.chars()
21898                            .flat_map(|codepoint| codepoint.to_lowercase())
21899                            .zip(query_start.to_lowercase())
21900                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21901                    })
21902                });
21903            }
21904
21905            let matched_strings = matches
21906                .into_iter()
21907                .map(|m| m.string)
21908                .collect::<HashSet<_>>();
21909
21910            completions.extend(snippets.iter().filter_map(|snippet| {
21911                let matching_prefix = snippet
21912                    .prefix
21913                    .iter()
21914                    .find(|prefix| matched_strings.contains(*prefix))?;
21915                let start = as_offset - last_word.len();
21916                let start = snapshot.anchor_before(start);
21917                let range = start..buffer_position;
21918                let lsp_start = to_lsp(&start);
21919                let lsp_range = lsp::Range {
21920                    start: lsp_start,
21921                    end: lsp_end,
21922                };
21923                Some(Completion {
21924                    replace_range: range,
21925                    new_text: snippet.body.clone(),
21926                    source: CompletionSource::Lsp {
21927                        insert_range: None,
21928                        server_id: LanguageServerId(usize::MAX),
21929                        resolved: true,
21930                        lsp_completion: Box::new(lsp::CompletionItem {
21931                            label: snippet.prefix.first().unwrap().clone(),
21932                            kind: Some(CompletionItemKind::SNIPPET),
21933                            label_details: snippet.description.as_ref().map(|description| {
21934                                lsp::CompletionItemLabelDetails {
21935                                    detail: Some(description.clone()),
21936                                    description: None,
21937                                }
21938                            }),
21939                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21940                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21941                                lsp::InsertReplaceEdit {
21942                                    new_text: snippet.body.clone(),
21943                                    insert: lsp_range,
21944                                    replace: lsp_range,
21945                                },
21946                            )),
21947                            filter_text: Some(snippet.body.clone()),
21948                            sort_text: Some(char::MAX.to_string()),
21949                            ..lsp::CompletionItem::default()
21950                        }),
21951                        lsp_defaults: None,
21952                    },
21953                    label: CodeLabel {
21954                        text: matching_prefix.clone(),
21955                        runs: Vec::new(),
21956                        filter_range: 0..matching_prefix.len(),
21957                    },
21958                    icon_path: None,
21959                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21960                        single_line: snippet.name.clone().into(),
21961                        plain_text: snippet
21962                            .description
21963                            .clone()
21964                            .map(|description| description.into()),
21965                    }),
21966                    insert_text_mode: None,
21967                    confirm: None,
21968                })
21969            }))
21970        }
21971
21972        Ok(CompletionResponse {
21973            completions,
21974            is_incomplete,
21975        })
21976    })
21977}
21978
21979impl CompletionProvider for Entity<Project> {
21980    fn completions(
21981        &self,
21982        _excerpt_id: ExcerptId,
21983        buffer: &Entity<Buffer>,
21984        buffer_position: text::Anchor,
21985        options: CompletionContext,
21986        _window: &mut Window,
21987        cx: &mut Context<Editor>,
21988    ) -> Task<Result<Vec<CompletionResponse>>> {
21989        self.update(cx, |project, cx| {
21990            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21991            let project_completions = project.completions(buffer, buffer_position, options, cx);
21992            cx.background_spawn(async move {
21993                let mut responses = project_completions.await?;
21994                let snippets = snippets.await?;
21995                if !snippets.completions.is_empty() {
21996                    responses.push(snippets);
21997                }
21998                Ok(responses)
21999            })
22000        })
22001    }
22002
22003    fn resolve_completions(
22004        &self,
22005        buffer: Entity<Buffer>,
22006        completion_indices: Vec<usize>,
22007        completions: Rc<RefCell<Box<[Completion]>>>,
22008        cx: &mut Context<Editor>,
22009    ) -> Task<Result<bool>> {
22010        self.update(cx, |project, cx| {
22011            project.lsp_store().update(cx, |lsp_store, cx| {
22012                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22013            })
22014        })
22015    }
22016
22017    fn apply_additional_edits_for_completion(
22018        &self,
22019        buffer: Entity<Buffer>,
22020        completions: Rc<RefCell<Box<[Completion]>>>,
22021        completion_index: usize,
22022        push_to_history: bool,
22023        cx: &mut Context<Editor>,
22024    ) -> Task<Result<Option<language::Transaction>>> {
22025        self.update(cx, |project, cx| {
22026            project.lsp_store().update(cx, |lsp_store, cx| {
22027                lsp_store.apply_additional_edits_for_completion(
22028                    buffer,
22029                    completions,
22030                    completion_index,
22031                    push_to_history,
22032                    cx,
22033                )
22034            })
22035        })
22036    }
22037
22038    fn is_completion_trigger(
22039        &self,
22040        buffer: &Entity<Buffer>,
22041        position: language::Anchor,
22042        text: &str,
22043        trigger_in_words: bool,
22044        menu_is_open: bool,
22045        cx: &mut Context<Editor>,
22046    ) -> bool {
22047        let mut chars = text.chars();
22048        let char = if let Some(char) = chars.next() {
22049            char
22050        } else {
22051            return false;
22052        };
22053        if chars.next().is_some() {
22054            return false;
22055        }
22056
22057        let buffer = buffer.read(cx);
22058        let snapshot = buffer.snapshot();
22059        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22060            return false;
22061        }
22062        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22063        if trigger_in_words && classifier.is_word(char) {
22064            return true;
22065        }
22066
22067        buffer.completion_triggers().contains(text)
22068    }
22069}
22070
22071impl SemanticsProvider for Entity<Project> {
22072    fn hover(
22073        &self,
22074        buffer: &Entity<Buffer>,
22075        position: text::Anchor,
22076        cx: &mut App,
22077    ) -> Option<Task<Vec<project::Hover>>> {
22078        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22079    }
22080
22081    fn document_highlights(
22082        &self,
22083        buffer: &Entity<Buffer>,
22084        position: text::Anchor,
22085        cx: &mut App,
22086    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22087        Some(self.update(cx, |project, cx| {
22088            project.document_highlights(buffer, position, cx)
22089        }))
22090    }
22091
22092    fn definitions(
22093        &self,
22094        buffer: &Entity<Buffer>,
22095        position: text::Anchor,
22096        kind: GotoDefinitionKind,
22097        cx: &mut App,
22098    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22099        Some(self.update(cx, |project, cx| match kind {
22100            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22101            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22102            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22103            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22104        }))
22105    }
22106
22107    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22108        // TODO: make this work for remote projects
22109        self.update(cx, |project, cx| {
22110            if project
22111                .active_debug_session(cx)
22112                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22113            {
22114                return true;
22115            }
22116
22117            buffer.update(cx, |buffer, cx| {
22118                project.any_language_server_supports_inlay_hints(buffer, cx)
22119            })
22120        })
22121    }
22122
22123    fn inline_values(
22124        &self,
22125        buffer_handle: Entity<Buffer>,
22126        range: Range<text::Anchor>,
22127        cx: &mut App,
22128    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22129        self.update(cx, |project, cx| {
22130            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22131
22132            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22133        })
22134    }
22135
22136    fn inlay_hints(
22137        &self,
22138        buffer_handle: Entity<Buffer>,
22139        range: Range<text::Anchor>,
22140        cx: &mut App,
22141    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22142        Some(self.update(cx, |project, cx| {
22143            project.inlay_hints(buffer_handle, range, cx)
22144        }))
22145    }
22146
22147    fn resolve_inlay_hint(
22148        &self,
22149        hint: InlayHint,
22150        buffer_handle: Entity<Buffer>,
22151        server_id: LanguageServerId,
22152        cx: &mut App,
22153    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22154        Some(self.update(cx, |project, cx| {
22155            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22156        }))
22157    }
22158
22159    fn range_for_rename(
22160        &self,
22161        buffer: &Entity<Buffer>,
22162        position: text::Anchor,
22163        cx: &mut App,
22164    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22165        Some(self.update(cx, |project, cx| {
22166            let buffer = buffer.clone();
22167            let task = project.prepare_rename(buffer.clone(), position, cx);
22168            cx.spawn(async move |_, cx| {
22169                Ok(match task.await? {
22170                    PrepareRenameResponse::Success(range) => Some(range),
22171                    PrepareRenameResponse::InvalidPosition => None,
22172                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22173                        // Fallback on using TreeSitter info to determine identifier range
22174                        buffer.read_with(cx, |buffer, _| {
22175                            let snapshot = buffer.snapshot();
22176                            let (range, kind) = snapshot.surrounding_word(position, false);
22177                            if kind != Some(CharKind::Word) {
22178                                return None;
22179                            }
22180                            Some(
22181                                snapshot.anchor_before(range.start)
22182                                    ..snapshot.anchor_after(range.end),
22183                            )
22184                        })?
22185                    }
22186                })
22187            })
22188        }))
22189    }
22190
22191    fn perform_rename(
22192        &self,
22193        buffer: &Entity<Buffer>,
22194        position: text::Anchor,
22195        new_name: String,
22196        cx: &mut App,
22197    ) -> Option<Task<Result<ProjectTransaction>>> {
22198        Some(self.update(cx, |project, cx| {
22199            project.perform_rename(buffer.clone(), position, new_name, cx)
22200        }))
22201    }
22202}
22203
22204fn inlay_hint_settings(
22205    location: Anchor,
22206    snapshot: &MultiBufferSnapshot,
22207    cx: &mut Context<Editor>,
22208) -> InlayHintSettings {
22209    let file = snapshot.file_at(location);
22210    let language = snapshot.language_at(location).map(|l| l.name());
22211    language_settings(language, file, cx).inlay_hints
22212}
22213
22214fn consume_contiguous_rows(
22215    contiguous_row_selections: &mut Vec<Selection<Point>>,
22216    selection: &Selection<Point>,
22217    display_map: &DisplaySnapshot,
22218    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22219) -> (MultiBufferRow, MultiBufferRow) {
22220    contiguous_row_selections.push(selection.clone());
22221    let start_row = MultiBufferRow(selection.start.row);
22222    let mut end_row = ending_row(selection, display_map);
22223
22224    while let Some(next_selection) = selections.peek() {
22225        if next_selection.start.row <= end_row.0 {
22226            end_row = ending_row(next_selection, display_map);
22227            contiguous_row_selections.push(selections.next().unwrap().clone());
22228        } else {
22229            break;
22230        }
22231    }
22232    (start_row, end_row)
22233}
22234
22235fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22236    if next_selection.end.column > 0 || next_selection.is_empty() {
22237        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22238    } else {
22239        MultiBufferRow(next_selection.end.row)
22240    }
22241}
22242
22243impl EditorSnapshot {
22244    pub fn remote_selections_in_range<'a>(
22245        &'a self,
22246        range: &'a Range<Anchor>,
22247        collaboration_hub: &dyn CollaborationHub,
22248        cx: &'a App,
22249    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22250        let participant_names = collaboration_hub.user_names(cx);
22251        let participant_indices = collaboration_hub.user_participant_indices(cx);
22252        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22253        let collaborators_by_replica_id = collaborators_by_peer_id
22254            .values()
22255            .map(|collaborator| (collaborator.replica_id, collaborator))
22256            .collect::<HashMap<_, _>>();
22257        self.buffer_snapshot
22258            .selections_in_range(range, false)
22259            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22260                if replica_id == AGENT_REPLICA_ID {
22261                    Some(RemoteSelection {
22262                        replica_id,
22263                        selection,
22264                        cursor_shape,
22265                        line_mode,
22266                        collaborator_id: CollaboratorId::Agent,
22267                        user_name: Some("Agent".into()),
22268                        color: cx.theme().players().agent(),
22269                    })
22270                } else {
22271                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22272                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22273                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22274                    Some(RemoteSelection {
22275                        replica_id,
22276                        selection,
22277                        cursor_shape,
22278                        line_mode,
22279                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22280                        user_name,
22281                        color: if let Some(index) = participant_index {
22282                            cx.theme().players().color_for_participant(index.0)
22283                        } else {
22284                            cx.theme().players().absent()
22285                        },
22286                    })
22287                }
22288            })
22289    }
22290
22291    pub fn hunks_for_ranges(
22292        &self,
22293        ranges: impl IntoIterator<Item = Range<Point>>,
22294    ) -> Vec<MultiBufferDiffHunk> {
22295        let mut hunks = Vec::new();
22296        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22297            HashMap::default();
22298        for query_range in ranges {
22299            let query_rows =
22300                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22301            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22302                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22303            ) {
22304                // Include deleted hunks that are adjacent to the query range, because
22305                // otherwise they would be missed.
22306                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22307                if hunk.status().is_deleted() {
22308                    intersects_range |= hunk.row_range.start == query_rows.end;
22309                    intersects_range |= hunk.row_range.end == query_rows.start;
22310                }
22311                if intersects_range {
22312                    if !processed_buffer_rows
22313                        .entry(hunk.buffer_id)
22314                        .or_default()
22315                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22316                    {
22317                        continue;
22318                    }
22319                    hunks.push(hunk);
22320                }
22321            }
22322        }
22323
22324        hunks
22325    }
22326
22327    fn display_diff_hunks_for_rows<'a>(
22328        &'a self,
22329        display_rows: Range<DisplayRow>,
22330        folded_buffers: &'a HashSet<BufferId>,
22331    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22332        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22333        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22334
22335        self.buffer_snapshot
22336            .diff_hunks_in_range(buffer_start..buffer_end)
22337            .filter_map(|hunk| {
22338                if folded_buffers.contains(&hunk.buffer_id) {
22339                    return None;
22340                }
22341
22342                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22343                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22344
22345                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22346                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22347
22348                let display_hunk = if hunk_display_start.column() != 0 {
22349                    DisplayDiffHunk::Folded {
22350                        display_row: hunk_display_start.row(),
22351                    }
22352                } else {
22353                    let mut end_row = hunk_display_end.row();
22354                    if hunk_display_end.column() > 0 {
22355                        end_row.0 += 1;
22356                    }
22357                    let is_created_file = hunk.is_created_file();
22358                    DisplayDiffHunk::Unfolded {
22359                        status: hunk.status(),
22360                        diff_base_byte_range: hunk.diff_base_byte_range,
22361                        display_row_range: hunk_display_start.row()..end_row,
22362                        multi_buffer_range: Anchor::range_in_buffer(
22363                            hunk.excerpt_id,
22364                            hunk.buffer_id,
22365                            hunk.buffer_range,
22366                        ),
22367                        is_created_file,
22368                    }
22369                };
22370
22371                Some(display_hunk)
22372            })
22373    }
22374
22375    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22376        self.display_snapshot.buffer_snapshot.language_at(position)
22377    }
22378
22379    pub fn is_focused(&self) -> bool {
22380        self.is_focused
22381    }
22382
22383    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22384        self.placeholder_text.as_ref()
22385    }
22386
22387    pub fn scroll_position(&self) -> gpui::Point<f32> {
22388        self.scroll_anchor.scroll_position(&self.display_snapshot)
22389    }
22390
22391    fn gutter_dimensions(
22392        &self,
22393        font_id: FontId,
22394        font_size: Pixels,
22395        max_line_number_width: Pixels,
22396        cx: &App,
22397    ) -> Option<GutterDimensions> {
22398        if !self.show_gutter {
22399            return None;
22400        }
22401
22402        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22403        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22404
22405        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22406            matches!(
22407                ProjectSettings::get_global(cx).git.git_gutter,
22408                Some(GitGutterSetting::TrackedFiles)
22409            )
22410        });
22411        let gutter_settings = EditorSettings::get_global(cx).gutter;
22412        let show_line_numbers = self
22413            .show_line_numbers
22414            .unwrap_or(gutter_settings.line_numbers);
22415        let line_gutter_width = if show_line_numbers {
22416            // Avoid flicker-like gutter resizes when the line number gains another digit by
22417            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22418            let min_width_for_number_on_gutter =
22419                ch_advance * gutter_settings.min_line_number_digits as f32;
22420            max_line_number_width.max(min_width_for_number_on_gutter)
22421        } else {
22422            0.0.into()
22423        };
22424
22425        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22426        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22427
22428        let git_blame_entries_width =
22429            self.git_blame_gutter_max_author_length
22430                .map(|max_author_length| {
22431                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22432                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22433
22434                    /// The number of characters to dedicate to gaps and margins.
22435                    const SPACING_WIDTH: usize = 4;
22436
22437                    let max_char_count = max_author_length.min(renderer.max_author_length())
22438                        + ::git::SHORT_SHA_LENGTH
22439                        + MAX_RELATIVE_TIMESTAMP.len()
22440                        + SPACING_WIDTH;
22441
22442                    ch_advance * max_char_count
22443                });
22444
22445        let is_singleton = self.buffer_snapshot.is_singleton();
22446
22447        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22448        left_padding += if !is_singleton {
22449            ch_width * 4.0
22450        } else if show_runnables || show_breakpoints {
22451            ch_width * 3.0
22452        } else if show_git_gutter && show_line_numbers {
22453            ch_width * 2.0
22454        } else if show_git_gutter || show_line_numbers {
22455            ch_width
22456        } else {
22457            px(0.)
22458        };
22459
22460        let shows_folds = is_singleton && gutter_settings.folds;
22461
22462        let right_padding = if shows_folds && show_line_numbers {
22463            ch_width * 4.0
22464        } else if shows_folds || (!is_singleton && show_line_numbers) {
22465            ch_width * 3.0
22466        } else if show_line_numbers {
22467            ch_width
22468        } else {
22469            px(0.)
22470        };
22471
22472        Some(GutterDimensions {
22473            left_padding,
22474            right_padding,
22475            width: line_gutter_width + left_padding + right_padding,
22476            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22477            git_blame_entries_width,
22478        })
22479    }
22480
22481    pub fn render_crease_toggle(
22482        &self,
22483        buffer_row: MultiBufferRow,
22484        row_contains_cursor: bool,
22485        editor: Entity<Editor>,
22486        window: &mut Window,
22487        cx: &mut App,
22488    ) -> Option<AnyElement> {
22489        let folded = self.is_line_folded(buffer_row);
22490        let mut is_foldable = false;
22491
22492        if let Some(crease) = self
22493            .crease_snapshot
22494            .query_row(buffer_row, &self.buffer_snapshot)
22495        {
22496            is_foldable = true;
22497            match crease {
22498                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22499                    if let Some(render_toggle) = render_toggle {
22500                        let toggle_callback =
22501                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22502                                if folded {
22503                                    editor.update(cx, |editor, cx| {
22504                                        editor.fold_at(buffer_row, window, cx)
22505                                    });
22506                                } else {
22507                                    editor.update(cx, |editor, cx| {
22508                                        editor.unfold_at(buffer_row, window, cx)
22509                                    });
22510                                }
22511                            });
22512                        return Some((render_toggle)(
22513                            buffer_row,
22514                            folded,
22515                            toggle_callback,
22516                            window,
22517                            cx,
22518                        ));
22519                    }
22520                }
22521            }
22522        }
22523
22524        is_foldable |= self.starts_indent(buffer_row);
22525
22526        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22527            Some(
22528                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22529                    .toggle_state(folded)
22530                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22531                        if folded {
22532                            this.unfold_at(buffer_row, window, cx);
22533                        } else {
22534                            this.fold_at(buffer_row, window, cx);
22535                        }
22536                    }))
22537                    .into_any_element(),
22538            )
22539        } else {
22540            None
22541        }
22542    }
22543
22544    pub fn render_crease_trailer(
22545        &self,
22546        buffer_row: MultiBufferRow,
22547        window: &mut Window,
22548        cx: &mut App,
22549    ) -> Option<AnyElement> {
22550        let folded = self.is_line_folded(buffer_row);
22551        if let Crease::Inline { render_trailer, .. } = self
22552            .crease_snapshot
22553            .query_row(buffer_row, &self.buffer_snapshot)?
22554        {
22555            let render_trailer = render_trailer.as_ref()?;
22556            Some(render_trailer(buffer_row, folded, window, cx))
22557        } else {
22558            None
22559        }
22560    }
22561}
22562
22563impl Deref for EditorSnapshot {
22564    type Target = DisplaySnapshot;
22565
22566    fn deref(&self) -> &Self::Target {
22567        &self.display_snapshot
22568    }
22569}
22570
22571#[derive(Clone, Debug, PartialEq, Eq)]
22572pub enum EditorEvent {
22573    InputIgnored {
22574        text: Arc<str>,
22575    },
22576    InputHandled {
22577        utf16_range_to_replace: Option<Range<isize>>,
22578        text: Arc<str>,
22579    },
22580    ExcerptsAdded {
22581        buffer: Entity<Buffer>,
22582        predecessor: ExcerptId,
22583        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22584    },
22585    ExcerptsRemoved {
22586        ids: Vec<ExcerptId>,
22587        removed_buffer_ids: Vec<BufferId>,
22588    },
22589    BufferFoldToggled {
22590        ids: Vec<ExcerptId>,
22591        folded: bool,
22592    },
22593    ExcerptsEdited {
22594        ids: Vec<ExcerptId>,
22595    },
22596    ExcerptsExpanded {
22597        ids: Vec<ExcerptId>,
22598    },
22599    BufferEdited,
22600    Edited {
22601        transaction_id: clock::Lamport,
22602    },
22603    Reparsed(BufferId),
22604    Focused,
22605    FocusedIn,
22606    Blurred,
22607    DirtyChanged,
22608    Saved,
22609    TitleChanged,
22610    DiffBaseChanged,
22611    SelectionsChanged {
22612        local: bool,
22613    },
22614    ScrollPositionChanged {
22615        local: bool,
22616        autoscroll: bool,
22617    },
22618    Closed,
22619    TransactionUndone {
22620        transaction_id: clock::Lamport,
22621    },
22622    TransactionBegun {
22623        transaction_id: clock::Lamport,
22624    },
22625    Reloaded,
22626    CursorShapeChanged,
22627    PushedToNavHistory {
22628        anchor: Anchor,
22629        is_deactivate: bool,
22630    },
22631}
22632
22633impl EventEmitter<EditorEvent> for Editor {}
22634
22635impl Focusable for Editor {
22636    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22637        self.focus_handle.clone()
22638    }
22639}
22640
22641impl Render for Editor {
22642    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22643        let settings = ThemeSettings::get_global(cx);
22644
22645        let mut text_style = match self.mode {
22646            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22647                color: cx.theme().colors().editor_foreground,
22648                font_family: settings.ui_font.family.clone(),
22649                font_features: settings.ui_font.features.clone(),
22650                font_fallbacks: settings.ui_font.fallbacks.clone(),
22651                font_size: rems(0.875).into(),
22652                font_weight: settings.ui_font.weight,
22653                line_height: relative(settings.buffer_line_height.value()),
22654                ..Default::default()
22655            },
22656            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22657                color: cx.theme().colors().editor_foreground,
22658                font_family: settings.buffer_font.family.clone(),
22659                font_features: settings.buffer_font.features.clone(),
22660                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22661                font_size: settings.buffer_font_size(cx).into(),
22662                font_weight: settings.buffer_font.weight,
22663                line_height: relative(settings.buffer_line_height.value()),
22664                ..Default::default()
22665            },
22666        };
22667        if let Some(text_style_refinement) = &self.text_style_refinement {
22668            text_style.refine(text_style_refinement)
22669        }
22670
22671        let background = match self.mode {
22672            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22673            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22674            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22675            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22676        };
22677
22678        EditorElement::new(
22679            &cx.entity(),
22680            EditorStyle {
22681                background,
22682                border: cx.theme().colors().border,
22683                local_player: cx.theme().players().local(),
22684                text: text_style,
22685                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22686                syntax: cx.theme().syntax().clone(),
22687                status: cx.theme().status().clone(),
22688                inlay_hints_style: make_inlay_hints_style(cx),
22689                inline_completion_styles: make_suggestion_styles(cx),
22690                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22691                show_underlines: self.diagnostics_enabled(),
22692            },
22693        )
22694    }
22695}
22696
22697impl EntityInputHandler for Editor {
22698    fn text_for_range(
22699        &mut self,
22700        range_utf16: Range<usize>,
22701        adjusted_range: &mut Option<Range<usize>>,
22702        _: &mut Window,
22703        cx: &mut Context<Self>,
22704    ) -> Option<String> {
22705        let snapshot = self.buffer.read(cx).read(cx);
22706        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22707        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22708        if (start.0..end.0) != range_utf16 {
22709            adjusted_range.replace(start.0..end.0);
22710        }
22711        Some(snapshot.text_for_range(start..end).collect())
22712    }
22713
22714    fn selected_text_range(
22715        &mut self,
22716        ignore_disabled_input: bool,
22717        _: &mut Window,
22718        cx: &mut Context<Self>,
22719    ) -> Option<UTF16Selection> {
22720        // Prevent the IME menu from appearing when holding down an alphabetic key
22721        // while input is disabled.
22722        if !ignore_disabled_input && !self.input_enabled {
22723            return None;
22724        }
22725
22726        let selection = self.selections.newest::<OffsetUtf16>(cx);
22727        let range = selection.range();
22728
22729        Some(UTF16Selection {
22730            range: range.start.0..range.end.0,
22731            reversed: selection.reversed,
22732        })
22733    }
22734
22735    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22736        let snapshot = self.buffer.read(cx).read(cx);
22737        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22738        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22739    }
22740
22741    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22742        self.clear_highlights::<InputComposition>(cx);
22743        self.ime_transaction.take();
22744    }
22745
22746    fn replace_text_in_range(
22747        &mut self,
22748        range_utf16: Option<Range<usize>>,
22749        text: &str,
22750        window: &mut Window,
22751        cx: &mut Context<Self>,
22752    ) {
22753        if !self.input_enabled {
22754            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22755            return;
22756        }
22757
22758        self.transact(window, cx, |this, window, cx| {
22759            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22760                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22761                Some(this.selection_replacement_ranges(range_utf16, cx))
22762            } else {
22763                this.marked_text_ranges(cx)
22764            };
22765
22766            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22767                let newest_selection_id = this.selections.newest_anchor().id;
22768                this.selections
22769                    .all::<OffsetUtf16>(cx)
22770                    .iter()
22771                    .zip(ranges_to_replace.iter())
22772                    .find_map(|(selection, range)| {
22773                        if selection.id == newest_selection_id {
22774                            Some(
22775                                (range.start.0 as isize - selection.head().0 as isize)
22776                                    ..(range.end.0 as isize - selection.head().0 as isize),
22777                            )
22778                        } else {
22779                            None
22780                        }
22781                    })
22782            });
22783
22784            cx.emit(EditorEvent::InputHandled {
22785                utf16_range_to_replace: range_to_replace,
22786                text: text.into(),
22787            });
22788
22789            if let Some(new_selected_ranges) = new_selected_ranges {
22790                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22791                    selections.select_ranges(new_selected_ranges)
22792                });
22793                this.backspace(&Default::default(), window, cx);
22794            }
22795
22796            this.handle_input(text, window, cx);
22797        });
22798
22799        if let Some(transaction) = self.ime_transaction {
22800            self.buffer.update(cx, |buffer, cx| {
22801                buffer.group_until_transaction(transaction, cx);
22802            });
22803        }
22804
22805        self.unmark_text(window, cx);
22806    }
22807
22808    fn replace_and_mark_text_in_range(
22809        &mut self,
22810        range_utf16: Option<Range<usize>>,
22811        text: &str,
22812        new_selected_range_utf16: Option<Range<usize>>,
22813        window: &mut Window,
22814        cx: &mut Context<Self>,
22815    ) {
22816        if !self.input_enabled {
22817            return;
22818        }
22819
22820        let transaction = self.transact(window, cx, |this, window, cx| {
22821            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22822                let snapshot = this.buffer.read(cx).read(cx);
22823                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22824                    for marked_range in &mut marked_ranges {
22825                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22826                        marked_range.start.0 += relative_range_utf16.start;
22827                        marked_range.start =
22828                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22829                        marked_range.end =
22830                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22831                    }
22832                }
22833                Some(marked_ranges)
22834            } else if let Some(range_utf16) = range_utf16 {
22835                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22836                Some(this.selection_replacement_ranges(range_utf16, cx))
22837            } else {
22838                None
22839            };
22840
22841            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22842                let newest_selection_id = this.selections.newest_anchor().id;
22843                this.selections
22844                    .all::<OffsetUtf16>(cx)
22845                    .iter()
22846                    .zip(ranges_to_replace.iter())
22847                    .find_map(|(selection, range)| {
22848                        if selection.id == newest_selection_id {
22849                            Some(
22850                                (range.start.0 as isize - selection.head().0 as isize)
22851                                    ..(range.end.0 as isize - selection.head().0 as isize),
22852                            )
22853                        } else {
22854                            None
22855                        }
22856                    })
22857            });
22858
22859            cx.emit(EditorEvent::InputHandled {
22860                utf16_range_to_replace: range_to_replace,
22861                text: text.into(),
22862            });
22863
22864            if let Some(ranges) = ranges_to_replace {
22865                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22866                    s.select_ranges(ranges)
22867                });
22868            }
22869
22870            let marked_ranges = {
22871                let snapshot = this.buffer.read(cx).read(cx);
22872                this.selections
22873                    .disjoint_anchors()
22874                    .iter()
22875                    .map(|selection| {
22876                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22877                    })
22878                    .collect::<Vec<_>>()
22879            };
22880
22881            if text.is_empty() {
22882                this.unmark_text(window, cx);
22883            } else {
22884                this.highlight_text::<InputComposition>(
22885                    marked_ranges.clone(),
22886                    HighlightStyle {
22887                        underline: Some(UnderlineStyle {
22888                            thickness: px(1.),
22889                            color: None,
22890                            wavy: false,
22891                        }),
22892                        ..Default::default()
22893                    },
22894                    cx,
22895                );
22896            }
22897
22898            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22899            let use_autoclose = this.use_autoclose;
22900            let use_auto_surround = this.use_auto_surround;
22901            this.set_use_autoclose(false);
22902            this.set_use_auto_surround(false);
22903            this.handle_input(text, window, cx);
22904            this.set_use_autoclose(use_autoclose);
22905            this.set_use_auto_surround(use_auto_surround);
22906
22907            if let Some(new_selected_range) = new_selected_range_utf16 {
22908                let snapshot = this.buffer.read(cx).read(cx);
22909                let new_selected_ranges = marked_ranges
22910                    .into_iter()
22911                    .map(|marked_range| {
22912                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22913                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22914                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22915                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22916                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22917                    })
22918                    .collect::<Vec<_>>();
22919
22920                drop(snapshot);
22921                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22922                    selections.select_ranges(new_selected_ranges)
22923                });
22924            }
22925        });
22926
22927        self.ime_transaction = self.ime_transaction.or(transaction);
22928        if let Some(transaction) = self.ime_transaction {
22929            self.buffer.update(cx, |buffer, cx| {
22930                buffer.group_until_transaction(transaction, cx);
22931            });
22932        }
22933
22934        if self.text_highlights::<InputComposition>(cx).is_none() {
22935            self.ime_transaction.take();
22936        }
22937    }
22938
22939    fn bounds_for_range(
22940        &mut self,
22941        range_utf16: Range<usize>,
22942        element_bounds: gpui::Bounds<Pixels>,
22943        window: &mut Window,
22944        cx: &mut Context<Self>,
22945    ) -> Option<gpui::Bounds<Pixels>> {
22946        let text_layout_details = self.text_layout_details(window);
22947        let CharacterDimensions {
22948            em_width,
22949            em_advance,
22950            line_height,
22951        } = self.character_dimensions(window);
22952
22953        let snapshot = self.snapshot(window, cx);
22954        let scroll_position = snapshot.scroll_position();
22955        let scroll_left = scroll_position.x * em_advance;
22956
22957        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22958        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22959            + self.gutter_dimensions.full_width();
22960        let y = line_height * (start.row().as_f32() - scroll_position.y);
22961
22962        Some(Bounds {
22963            origin: element_bounds.origin + point(x, y),
22964            size: size(em_width, line_height),
22965        })
22966    }
22967
22968    fn character_index_for_point(
22969        &mut self,
22970        point: gpui::Point<Pixels>,
22971        _window: &mut Window,
22972        _cx: &mut Context<Self>,
22973    ) -> Option<usize> {
22974        let position_map = self.last_position_map.as_ref()?;
22975        if !position_map.text_hitbox.contains(&point) {
22976            return None;
22977        }
22978        let display_point = position_map.point_for_position(point).previous_valid;
22979        let anchor = position_map
22980            .snapshot
22981            .display_point_to_anchor(display_point, Bias::Left);
22982        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22983        Some(utf16_offset.0)
22984    }
22985}
22986
22987trait SelectionExt {
22988    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22989    fn spanned_rows(
22990        &self,
22991        include_end_if_at_line_start: bool,
22992        map: &DisplaySnapshot,
22993    ) -> Range<MultiBufferRow>;
22994}
22995
22996impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22997    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22998        let start = self
22999            .start
23000            .to_point(&map.buffer_snapshot)
23001            .to_display_point(map);
23002        let end = self
23003            .end
23004            .to_point(&map.buffer_snapshot)
23005            .to_display_point(map);
23006        if self.reversed {
23007            end..start
23008        } else {
23009            start..end
23010        }
23011    }
23012
23013    fn spanned_rows(
23014        &self,
23015        include_end_if_at_line_start: bool,
23016        map: &DisplaySnapshot,
23017    ) -> Range<MultiBufferRow> {
23018        let start = self.start.to_point(&map.buffer_snapshot);
23019        let mut end = self.end.to_point(&map.buffer_snapshot);
23020        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23021            end.row -= 1;
23022        }
23023
23024        let buffer_start = map.prev_line_boundary(start).0;
23025        let buffer_end = map.next_line_boundary(end).0;
23026        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23027    }
23028}
23029
23030impl<T: InvalidationRegion> InvalidationStack<T> {
23031    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23032    where
23033        S: Clone + ToOffset,
23034    {
23035        while let Some(region) = self.last() {
23036            let all_selections_inside_invalidation_ranges =
23037                if selections.len() == region.ranges().len() {
23038                    selections
23039                        .iter()
23040                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23041                        .all(|(selection, invalidation_range)| {
23042                            let head = selection.head().to_offset(buffer);
23043                            invalidation_range.start <= head && invalidation_range.end >= head
23044                        })
23045                } else {
23046                    false
23047                };
23048
23049            if all_selections_inside_invalidation_ranges {
23050                break;
23051            } else {
23052                self.pop();
23053            }
23054        }
23055    }
23056}
23057
23058impl<T> Default for InvalidationStack<T> {
23059    fn default() -> Self {
23060        Self(Default::default())
23061    }
23062}
23063
23064impl<T> Deref for InvalidationStack<T> {
23065    type Target = Vec<T>;
23066
23067    fn deref(&self) -> &Self::Target {
23068        &self.0
23069    }
23070}
23071
23072impl<T> DerefMut for InvalidationStack<T> {
23073    fn deref_mut(&mut self) -> &mut Self::Target {
23074        &mut self.0
23075    }
23076}
23077
23078impl InvalidationRegion for SnippetState {
23079    fn ranges(&self) -> &[Range<Anchor>] {
23080        &self.ranges[self.active_index]
23081    }
23082}
23083
23084fn inline_completion_edit_text(
23085    current_snapshot: &BufferSnapshot,
23086    edits: &[(Range<Anchor>, String)],
23087    edit_preview: &EditPreview,
23088    include_deletions: bool,
23089    cx: &App,
23090) -> HighlightedText {
23091    let edits = edits
23092        .iter()
23093        .map(|(anchor, text)| {
23094            (
23095                anchor.start.text_anchor..anchor.end.text_anchor,
23096                text.clone(),
23097            )
23098        })
23099        .collect::<Vec<_>>();
23100
23101    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23102}
23103
23104pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23105    match severity {
23106        lsp::DiagnosticSeverity::ERROR => colors.error,
23107        lsp::DiagnosticSeverity::WARNING => colors.warning,
23108        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23109        lsp::DiagnosticSeverity::HINT => colors.info,
23110        _ => colors.ignored,
23111    }
23112}
23113
23114pub fn styled_runs_for_code_label<'a>(
23115    label: &'a CodeLabel,
23116    syntax_theme: &'a theme::SyntaxTheme,
23117) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23118    let fade_out = HighlightStyle {
23119        fade_out: Some(0.35),
23120        ..Default::default()
23121    };
23122
23123    let mut prev_end = label.filter_range.end;
23124    label
23125        .runs
23126        .iter()
23127        .enumerate()
23128        .flat_map(move |(ix, (range, highlight_id))| {
23129            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23130                style
23131            } else {
23132                return Default::default();
23133            };
23134            let mut muted_style = style;
23135            muted_style.highlight(fade_out);
23136
23137            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23138            if range.start >= label.filter_range.end {
23139                if range.start > prev_end {
23140                    runs.push((prev_end..range.start, fade_out));
23141                }
23142                runs.push((range.clone(), muted_style));
23143            } else if range.end <= label.filter_range.end {
23144                runs.push((range.clone(), style));
23145            } else {
23146                runs.push((range.start..label.filter_range.end, style));
23147                runs.push((label.filter_range.end..range.end, muted_style));
23148            }
23149            prev_end = cmp::max(prev_end, range.end);
23150
23151            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23152                runs.push((prev_end..label.text.len(), fade_out));
23153            }
23154
23155            runs
23156        })
23157}
23158
23159pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23160    let mut prev_index = 0;
23161    let mut prev_codepoint: Option<char> = None;
23162    text.char_indices()
23163        .chain([(text.len(), '\0')])
23164        .filter_map(move |(index, codepoint)| {
23165            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23166            let is_boundary = index == text.len()
23167                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23168                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23169            if is_boundary {
23170                let chunk = &text[prev_index..index];
23171                prev_index = index;
23172                Some(chunk)
23173            } else {
23174                None
23175            }
23176        })
23177}
23178
23179pub trait RangeToAnchorExt: Sized {
23180    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23181
23182    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23183        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23184        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23185    }
23186}
23187
23188impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23189    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23190        let start_offset = self.start.to_offset(snapshot);
23191        let end_offset = self.end.to_offset(snapshot);
23192        if start_offset == end_offset {
23193            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23194        } else {
23195            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23196        }
23197    }
23198}
23199
23200pub trait RowExt {
23201    fn as_f32(&self) -> f32;
23202
23203    fn next_row(&self) -> Self;
23204
23205    fn previous_row(&self) -> Self;
23206
23207    fn minus(&self, other: Self) -> u32;
23208}
23209
23210impl RowExt for DisplayRow {
23211    fn as_f32(&self) -> f32 {
23212        self.0 as f32
23213    }
23214
23215    fn next_row(&self) -> Self {
23216        Self(self.0 + 1)
23217    }
23218
23219    fn previous_row(&self) -> Self {
23220        Self(self.0.saturating_sub(1))
23221    }
23222
23223    fn minus(&self, other: Self) -> u32 {
23224        self.0 - other.0
23225    }
23226}
23227
23228impl RowExt for MultiBufferRow {
23229    fn as_f32(&self) -> f32 {
23230        self.0 as f32
23231    }
23232
23233    fn next_row(&self) -> Self {
23234        Self(self.0 + 1)
23235    }
23236
23237    fn previous_row(&self) -> Self {
23238        Self(self.0.saturating_sub(1))
23239    }
23240
23241    fn minus(&self, other: Self) -> u32 {
23242        self.0 - other.0
23243    }
23244}
23245
23246trait RowRangeExt {
23247    type Row;
23248
23249    fn len(&self) -> usize;
23250
23251    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23252}
23253
23254impl RowRangeExt for Range<MultiBufferRow> {
23255    type Row = MultiBufferRow;
23256
23257    fn len(&self) -> usize {
23258        (self.end.0 - self.start.0) as usize
23259    }
23260
23261    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23262        (self.start.0..self.end.0).map(MultiBufferRow)
23263    }
23264}
23265
23266impl RowRangeExt for Range<DisplayRow> {
23267    type Row = DisplayRow;
23268
23269    fn len(&self) -> usize {
23270        (self.end.0 - self.start.0) as usize
23271    }
23272
23273    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23274        (self.start.0..self.end.0).map(DisplayRow)
23275    }
23276}
23277
23278/// If select range has more than one line, we
23279/// just point the cursor to range.start.
23280fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23281    if range.start.row == range.end.row {
23282        range
23283    } else {
23284        range.start..range.start
23285    }
23286}
23287pub struct KillRing(ClipboardItem);
23288impl Global for KillRing {}
23289
23290const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23291
23292enum BreakpointPromptEditAction {
23293    Log,
23294    Condition,
23295    HitCondition,
23296}
23297
23298struct BreakpointPromptEditor {
23299    pub(crate) prompt: Entity<Editor>,
23300    editor: WeakEntity<Editor>,
23301    breakpoint_anchor: Anchor,
23302    breakpoint: Breakpoint,
23303    edit_action: BreakpointPromptEditAction,
23304    block_ids: HashSet<CustomBlockId>,
23305    editor_margins: Arc<Mutex<EditorMargins>>,
23306    _subscriptions: Vec<Subscription>,
23307}
23308
23309impl BreakpointPromptEditor {
23310    const MAX_LINES: u8 = 4;
23311
23312    fn new(
23313        editor: WeakEntity<Editor>,
23314        breakpoint_anchor: Anchor,
23315        breakpoint: Breakpoint,
23316        edit_action: BreakpointPromptEditAction,
23317        window: &mut Window,
23318        cx: &mut Context<Self>,
23319    ) -> Self {
23320        let base_text = match edit_action {
23321            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23322            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23323            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23324        }
23325        .map(|msg| msg.to_string())
23326        .unwrap_or_default();
23327
23328        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23329        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23330
23331        let prompt = cx.new(|cx| {
23332            let mut prompt = Editor::new(
23333                EditorMode::AutoHeight {
23334                    min_lines: 1,
23335                    max_lines: Some(Self::MAX_LINES as usize),
23336                },
23337                buffer,
23338                None,
23339                window,
23340                cx,
23341            );
23342            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23343            prompt.set_show_cursor_when_unfocused(false, cx);
23344            prompt.set_placeholder_text(
23345                match edit_action {
23346                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23347                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23348                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23349                },
23350                cx,
23351            );
23352
23353            prompt
23354        });
23355
23356        Self {
23357            prompt,
23358            editor,
23359            breakpoint_anchor,
23360            breakpoint,
23361            edit_action,
23362            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23363            block_ids: Default::default(),
23364            _subscriptions: vec![],
23365        }
23366    }
23367
23368    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23369        self.block_ids.extend(block_ids)
23370    }
23371
23372    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23373        if let Some(editor) = self.editor.upgrade() {
23374            let message = self
23375                .prompt
23376                .read(cx)
23377                .buffer
23378                .read(cx)
23379                .as_singleton()
23380                .expect("A multi buffer in breakpoint prompt isn't possible")
23381                .read(cx)
23382                .as_rope()
23383                .to_string();
23384
23385            editor.update(cx, |editor, cx| {
23386                editor.edit_breakpoint_at_anchor(
23387                    self.breakpoint_anchor,
23388                    self.breakpoint.clone(),
23389                    match self.edit_action {
23390                        BreakpointPromptEditAction::Log => {
23391                            BreakpointEditAction::EditLogMessage(message.into())
23392                        }
23393                        BreakpointPromptEditAction::Condition => {
23394                            BreakpointEditAction::EditCondition(message.into())
23395                        }
23396                        BreakpointPromptEditAction::HitCondition => {
23397                            BreakpointEditAction::EditHitCondition(message.into())
23398                        }
23399                    },
23400                    cx,
23401                );
23402
23403                editor.remove_blocks(self.block_ids.clone(), None, cx);
23404                cx.focus_self(window);
23405            });
23406        }
23407    }
23408
23409    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23410        self.editor
23411            .update(cx, |editor, cx| {
23412                editor.remove_blocks(self.block_ids.clone(), None, cx);
23413                window.focus(&editor.focus_handle);
23414            })
23415            .log_err();
23416    }
23417
23418    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23419        let settings = ThemeSettings::get_global(cx);
23420        let text_style = TextStyle {
23421            color: if self.prompt.read(cx).read_only(cx) {
23422                cx.theme().colors().text_disabled
23423            } else {
23424                cx.theme().colors().text
23425            },
23426            font_family: settings.buffer_font.family.clone(),
23427            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23428            font_size: settings.buffer_font_size(cx).into(),
23429            font_weight: settings.buffer_font.weight,
23430            line_height: relative(settings.buffer_line_height.value()),
23431            ..Default::default()
23432        };
23433        EditorElement::new(
23434            &self.prompt,
23435            EditorStyle {
23436                background: cx.theme().colors().editor_background,
23437                local_player: cx.theme().players().local(),
23438                text: text_style,
23439                ..Default::default()
23440            },
23441        )
23442    }
23443}
23444
23445impl Render for BreakpointPromptEditor {
23446    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23447        let editor_margins = *self.editor_margins.lock();
23448        let gutter_dimensions = editor_margins.gutter;
23449        h_flex()
23450            .key_context("Editor")
23451            .bg(cx.theme().colors().editor_background)
23452            .border_y_1()
23453            .border_color(cx.theme().status().info_border)
23454            .size_full()
23455            .py(window.line_height() / 2.5)
23456            .on_action(cx.listener(Self::confirm))
23457            .on_action(cx.listener(Self::cancel))
23458            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23459            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23460    }
23461}
23462
23463impl Focusable for BreakpointPromptEditor {
23464    fn focus_handle(&self, cx: &App) -> FocusHandle {
23465        self.prompt.focus_handle(cx)
23466    }
23467}
23468
23469fn all_edits_insertions_or_deletions(
23470    edits: &Vec<(Range<Anchor>, String)>,
23471    snapshot: &MultiBufferSnapshot,
23472) -> bool {
23473    let mut all_insertions = true;
23474    let mut all_deletions = true;
23475
23476    for (range, new_text) in edits.iter() {
23477        let range_is_empty = range.to_offset(&snapshot).is_empty();
23478        let text_is_empty = new_text.is_empty();
23479
23480        if range_is_empty != text_is_empty {
23481            if range_is_empty {
23482                all_deletions = false;
23483            } else {
23484                all_insertions = false;
23485            }
23486        } else {
23487            return false;
23488        }
23489
23490        if !all_insertions && !all_deletions {
23491            return false;
23492        }
23493    }
23494    all_insertions || all_deletions
23495}
23496
23497struct MissingEditPredictionKeybindingTooltip;
23498
23499impl Render for MissingEditPredictionKeybindingTooltip {
23500    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23501        ui::tooltip_container(window, cx, |container, _, cx| {
23502            container
23503                .flex_shrink_0()
23504                .max_w_80()
23505                .min_h(rems_from_px(124.))
23506                .justify_between()
23507                .child(
23508                    v_flex()
23509                        .flex_1()
23510                        .text_ui_sm(cx)
23511                        .child(Label::new("Conflict with Accept Keybinding"))
23512                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23513                )
23514                .child(
23515                    h_flex()
23516                        .pb_1()
23517                        .gap_1()
23518                        .items_end()
23519                        .w_full()
23520                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23521                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23522                        }))
23523                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23524                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23525                        })),
23526                )
23527        })
23528    }
23529}
23530
23531#[derive(Debug, Clone, Copy, PartialEq)]
23532pub struct LineHighlight {
23533    pub background: Background,
23534    pub border: Option<gpui::Hsla>,
23535    pub include_gutter: bool,
23536    pub type_id: Option<TypeId>,
23537}
23538
23539struct LineManipulationResult {
23540    pub new_text: String,
23541    pub line_count_before: usize,
23542    pub line_count_after: usize,
23543}
23544
23545fn render_diff_hunk_controls(
23546    row: u32,
23547    status: &DiffHunkStatus,
23548    hunk_range: Range<Anchor>,
23549    is_created_file: bool,
23550    line_height: Pixels,
23551    editor: &Entity<Editor>,
23552    _window: &mut Window,
23553    cx: &mut App,
23554) -> AnyElement {
23555    h_flex()
23556        .h(line_height)
23557        .mr_1()
23558        .gap_1()
23559        .px_0p5()
23560        .pb_1()
23561        .border_x_1()
23562        .border_b_1()
23563        .border_color(cx.theme().colors().border_variant)
23564        .rounded_b_lg()
23565        .bg(cx.theme().colors().editor_background)
23566        .gap_1()
23567        .block_mouse_except_scroll()
23568        .shadow_md()
23569        .child(if status.has_secondary_hunk() {
23570            Button::new(("stage", row as u64), "Stage")
23571                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23572                .tooltip({
23573                    let focus_handle = editor.focus_handle(cx);
23574                    move |window, cx| {
23575                        Tooltip::for_action_in(
23576                            "Stage Hunk",
23577                            &::git::ToggleStaged,
23578                            &focus_handle,
23579                            window,
23580                            cx,
23581                        )
23582                    }
23583                })
23584                .on_click({
23585                    let editor = editor.clone();
23586                    move |_event, _window, cx| {
23587                        editor.update(cx, |editor, cx| {
23588                            editor.stage_or_unstage_diff_hunks(
23589                                true,
23590                                vec![hunk_range.start..hunk_range.start],
23591                                cx,
23592                            );
23593                        });
23594                    }
23595                })
23596        } else {
23597            Button::new(("unstage", row as u64), "Unstage")
23598                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23599                .tooltip({
23600                    let focus_handle = editor.focus_handle(cx);
23601                    move |window, cx| {
23602                        Tooltip::for_action_in(
23603                            "Unstage Hunk",
23604                            &::git::ToggleStaged,
23605                            &focus_handle,
23606                            window,
23607                            cx,
23608                        )
23609                    }
23610                })
23611                .on_click({
23612                    let editor = editor.clone();
23613                    move |_event, _window, cx| {
23614                        editor.update(cx, |editor, cx| {
23615                            editor.stage_or_unstage_diff_hunks(
23616                                false,
23617                                vec![hunk_range.start..hunk_range.start],
23618                                cx,
23619                            );
23620                        });
23621                    }
23622                })
23623        })
23624        .child(
23625            Button::new(("restore", row as u64), "Restore")
23626                .tooltip({
23627                    let focus_handle = editor.focus_handle(cx);
23628                    move |window, cx| {
23629                        Tooltip::for_action_in(
23630                            "Restore Hunk",
23631                            &::git::Restore,
23632                            &focus_handle,
23633                            window,
23634                            cx,
23635                        )
23636                    }
23637                })
23638                .on_click({
23639                    let editor = editor.clone();
23640                    move |_event, window, cx| {
23641                        editor.update(cx, |editor, cx| {
23642                            let snapshot = editor.snapshot(window, cx);
23643                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23644                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23645                        });
23646                    }
23647                })
23648                .disabled(is_created_file),
23649        )
23650        .when(
23651            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23652            |el| {
23653                el.child(
23654                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23655                        .shape(IconButtonShape::Square)
23656                        .icon_size(IconSize::Small)
23657                        // .disabled(!has_multiple_hunks)
23658                        .tooltip({
23659                            let focus_handle = editor.focus_handle(cx);
23660                            move |window, cx| {
23661                                Tooltip::for_action_in(
23662                                    "Next Hunk",
23663                                    &GoToHunk,
23664                                    &focus_handle,
23665                                    window,
23666                                    cx,
23667                                )
23668                            }
23669                        })
23670                        .on_click({
23671                            let editor = editor.clone();
23672                            move |_event, window, cx| {
23673                                editor.update(cx, |editor, cx| {
23674                                    let snapshot = editor.snapshot(window, cx);
23675                                    let position =
23676                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23677                                    editor.go_to_hunk_before_or_after_position(
23678                                        &snapshot,
23679                                        position,
23680                                        Direction::Next,
23681                                        window,
23682                                        cx,
23683                                    );
23684                                    editor.expand_selected_diff_hunks(cx);
23685                                });
23686                            }
23687                        }),
23688                )
23689                .child(
23690                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23691                        .shape(IconButtonShape::Square)
23692                        .icon_size(IconSize::Small)
23693                        // .disabled(!has_multiple_hunks)
23694                        .tooltip({
23695                            let focus_handle = editor.focus_handle(cx);
23696                            move |window, cx| {
23697                                Tooltip::for_action_in(
23698                                    "Previous Hunk",
23699                                    &GoToPreviousHunk,
23700                                    &focus_handle,
23701                                    window,
23702                                    cx,
23703                                )
23704                            }
23705                        })
23706                        .on_click({
23707                            let editor = editor.clone();
23708                            move |_event, window, cx| {
23709                                editor.update(cx, |editor, cx| {
23710                                    let snapshot = editor.snapshot(window, cx);
23711                                    let point =
23712                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23713                                    editor.go_to_hunk_before_or_after_position(
23714                                        &snapshot,
23715                                        point,
23716                                        Direction::Prev,
23717                                        window,
23718                                        cx,
23719                                    );
23720                                    editor.expand_selected_diff_hunks(cx);
23721                                });
23722                            }
23723                        }),
23724                )
23725            },
23726        )
23727        .into_any_element()
23728}