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, DisableAiSettings, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, Capability, CharKind,
  113    CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview,
  114    HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
  115    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216use zed_actions;
  217
  218use crate::{
  219    code_context_menus::CompletionsMenuSource,
  220    hover_links::{find_url, find_url_from_range},
  221};
  222use crate::{
  223    editor_settings::MultiCursorModifier,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    DebuggerValue(usize),
  280    // LSP
  281    Hint(usize),
  282    Color(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::DebuggerValue(id) => *id,
  290            Self::Hint(id) => *id,
  291            Self::Color(id) => *id,
  292        }
  293    }
  294}
  295
  296pub enum ActiveDebugLine {}
  297pub enum DebugStackFrameLine {}
  298enum DocumentHighlightRead {}
  299enum DocumentHighlightWrite {}
  300enum InputComposition {}
  301pub enum PendingInput {}
  302enum SelectedTextHighlight {}
  303
  304pub enum ConflictsOuter {}
  305pub enum ConflictsOurs {}
  306pub enum ConflictsTheirs {}
  307pub enum ConflictsOursMarker {}
  308pub enum ConflictsTheirsMarker {}
  309
  310#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  311pub enum Navigated {
  312    Yes,
  313    No,
  314}
  315
  316impl Navigated {
  317    pub fn from_bool(yes: bool) -> Navigated {
  318        if yes { Navigated::Yes } else { Navigated::No }
  319    }
  320}
  321
  322#[derive(Debug, Clone, PartialEq, Eq)]
  323enum DisplayDiffHunk {
  324    Folded {
  325        display_row: DisplayRow,
  326    },
  327    Unfolded {
  328        is_created_file: bool,
  329        diff_base_byte_range: Range<usize>,
  330        display_row_range: Range<DisplayRow>,
  331        multi_buffer_range: Range<Anchor>,
  332        status: DiffHunkStatus,
  333    },
  334}
  335
  336pub enum HideMouseCursorOrigin {
  337    TypingAction,
  338    MovementAction,
  339}
  340
  341pub fn init_settings(cx: &mut App) {
  342    EditorSettings::register(cx);
  343}
  344
  345pub fn init(cx: &mut App) {
  346    init_settings(cx);
  347
  348    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  349
  350    workspace::register_project_item::<Editor>(cx);
  351    workspace::FollowableViewRegistry::register::<Editor>(cx);
  352    workspace::register_serializable_item::<Editor>(cx);
  353
  354    cx.observe_new(
  355        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  356            workspace.register_action(Editor::new_file);
  357            workspace.register_action(Editor::new_file_vertical);
  358            workspace.register_action(Editor::new_file_horizontal);
  359            workspace.register_action(Editor::cancel_language_server_work);
  360            workspace.register_action(Editor::toggle_focus);
  361        },
  362    )
  363    .detach();
  364
  365    cx.on_action(move |_: &workspace::NewFile, cx| {
  366        let app_state = workspace::AppState::global(cx);
  367        if let Some(app_state) = app_state.upgrade() {
  368            workspace::open_new(
  369                Default::default(),
  370                app_state,
  371                cx,
  372                |workspace, window, cx| {
  373                    Editor::new_file(workspace, &Default::default(), window, cx)
  374                },
  375            )
  376            .detach();
  377        }
  378    });
  379    cx.on_action(move |_: &workspace::NewWindow, cx| {
  380        let app_state = workspace::AppState::global(cx);
  381        if let Some(app_state) = app_state.upgrade() {
  382            workspace::open_new(
  383                Default::default(),
  384                app_state,
  385                cx,
  386                |workspace, window, cx| {
  387                    cx.activate(true);
  388                    Editor::new_file(workspace, &Default::default(), window, cx)
  389                },
  390            )
  391            .detach();
  392        }
  393    });
  394}
  395
  396pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  397    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  398}
  399
  400pub trait DiagnosticRenderer {
  401    fn render_group(
  402        &self,
  403        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  404        buffer_id: BufferId,
  405        snapshot: EditorSnapshot,
  406        editor: WeakEntity<Editor>,
  407        cx: &mut App,
  408    ) -> Vec<BlockProperties<Anchor>>;
  409
  410    fn render_hover(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        range: Range<Point>,
  414        buffer_id: BufferId,
  415        cx: &mut App,
  416    ) -> Option<Entity<markdown::Markdown>>;
  417
  418    fn open_link(
  419        &self,
  420        editor: &mut Editor,
  421        link: SharedString,
  422        window: &mut Window,
  423        cx: &mut Context<Editor>,
  424    );
  425}
  426
  427pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  428
  429impl GlobalDiagnosticRenderer {
  430    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  431        cx.try_global::<Self>().map(|g| g.0.clone())
  432    }
  433}
  434
  435impl gpui::Global for GlobalDiagnosticRenderer {}
  436pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  437    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  438}
  439
  440pub struct SearchWithinRange;
  441
  442trait InvalidationRegion {
  443    fn ranges(&self) -> &[Range<Anchor>];
  444}
  445
  446#[derive(Clone, Debug, PartialEq)]
  447pub enum SelectPhase {
  448    Begin {
  449        position: DisplayPoint,
  450        add: bool,
  451        click_count: usize,
  452    },
  453    BeginColumnar {
  454        position: DisplayPoint,
  455        reset: bool,
  456        mode: ColumnarMode,
  457        goal_column: u32,
  458    },
  459    Extend {
  460        position: DisplayPoint,
  461        click_count: usize,
  462    },
  463    Update {
  464        position: DisplayPoint,
  465        goal_column: u32,
  466        scroll_delta: gpui::Point<f32>,
  467    },
  468    End,
  469}
  470
  471#[derive(Clone, Debug, PartialEq)]
  472pub enum ColumnarMode {
  473    FromMouse,
  474    FromSelection,
  475}
  476
  477#[derive(Clone, Debug)]
  478pub enum SelectMode {
  479    Character,
  480    Word(Range<Anchor>),
  481    Line(Range<Anchor>),
  482    All,
  483}
  484
  485#[derive(Clone, PartialEq, Eq, Debug)]
  486pub enum EditorMode {
  487    SingleLine,
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954    keyboard_grace: bool,
  955}
  956
  957enum SelectionDragState {
  958    /// State when no drag related activity is detected.
  959    None,
  960    /// State when the mouse is down on a selection that is about to be dragged.
  961    ReadyToDrag {
  962        selection: Selection<Anchor>,
  963        click_position: gpui::Point<Pixels>,
  964        mouse_down_time: Instant,
  965    },
  966    /// State when the mouse is dragging the selection in the editor.
  967    Dragging {
  968        selection: Selection<Anchor>,
  969        drop_cursor: Selection<Anchor>,
  970        hide_drop_cursor: bool,
  971    },
  972}
  973
  974enum ColumnarSelectionState {
  975    FromMouse {
  976        selection_tail: Anchor,
  977        display_point: Option<DisplayPoint>,
  978    },
  979    FromSelection {
  980        selection_tail: Anchor,
  981    },
  982}
  983
  984/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  985/// a breakpoint on them.
  986#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  987struct PhantomBreakpointIndicator {
  988    display_row: DisplayRow,
  989    /// There's a small debounce between hovering over the line and showing the indicator.
  990    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  991    is_active: bool,
  992    collides_with_existing_breakpoint: bool,
  993}
  994
  995/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  996///
  997/// See the [module level documentation](self) for more information.
  998pub struct Editor {
  999    focus_handle: FocusHandle,
 1000    last_focused_descendant: Option<WeakFocusHandle>,
 1001    /// The text buffer being edited
 1002    buffer: Entity<MultiBuffer>,
 1003    /// Map of how text in the buffer should be displayed.
 1004    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1005    pub display_map: Entity<DisplayMap>,
 1006    pub selections: SelectionsCollection,
 1007    pub scroll_manager: ScrollManager,
 1008    /// When inline assist editors are linked, they all render cursors because
 1009    /// typing enters text into each of them, even the ones that aren't focused.
 1010    pub(crate) show_cursor_when_unfocused: bool,
 1011    columnar_selection_state: Option<ColumnarSelectionState>,
 1012    add_selections_state: Option<AddSelectionsState>,
 1013    select_next_state: Option<SelectNextState>,
 1014    select_prev_state: Option<SelectNextState>,
 1015    selection_history: SelectionHistory,
 1016    defer_selection_effects: bool,
 1017    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1018    autoclose_regions: Vec<AutocloseRegion>,
 1019    snippet_stack: InvalidationStack<SnippetState>,
 1020    select_syntax_node_history: SelectSyntaxNodeHistory,
 1021    ime_transaction: Option<TransactionId>,
 1022    pub diagnostics_max_severity: DiagnosticSeverity,
 1023    active_diagnostics: ActiveDiagnostic,
 1024    show_inline_diagnostics: bool,
 1025    inline_diagnostics_update: Task<()>,
 1026    inline_diagnostics_enabled: bool,
 1027    diagnostics_enabled: bool,
 1028    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1029    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1030    hard_wrap: Option<usize>,
 1031
 1032    // TODO: make this a access method
 1033    pub project: Option<Entity<Project>>,
 1034    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1035    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1036    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1037    blink_manager: Entity<BlinkManager>,
 1038    show_cursor_names: bool,
 1039    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1040    pub show_local_selections: bool,
 1041    mode: EditorMode,
 1042    show_breadcrumbs: bool,
 1043    show_gutter: bool,
 1044    show_scrollbars: ScrollbarAxes,
 1045    minimap_visibility: MinimapVisibility,
 1046    offset_content: bool,
 1047    disable_expand_excerpt_buttons: bool,
 1048    show_line_numbers: Option<bool>,
 1049    use_relative_line_numbers: Option<bool>,
 1050    show_git_diff_gutter: Option<bool>,
 1051    show_code_actions: Option<bool>,
 1052    show_runnables: Option<bool>,
 1053    show_breakpoints: Option<bool>,
 1054    show_wrap_guides: Option<bool>,
 1055    show_indent_guides: Option<bool>,
 1056    placeholder_text: Option<Arc<str>>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_inline_completion: Option<InlineCompletionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    inline_completions_hidden_for_vim_mode: bool,
 1104    show_inline_completions_override: Option<bool>,
 1105    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177}
 1178
 1179#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1180enum NextScrollCursorCenterTopBottom {
 1181    #[default]
 1182    Center,
 1183    Top,
 1184    Bottom,
 1185}
 1186
 1187impl NextScrollCursorCenterTopBottom {
 1188    fn next(&self) -> Self {
 1189        match self {
 1190            Self::Center => Self::Top,
 1191            Self::Top => Self::Bottom,
 1192            Self::Bottom => Self::Center,
 1193        }
 1194    }
 1195}
 1196
 1197#[derive(Clone)]
 1198pub struct EditorSnapshot {
 1199    pub mode: EditorMode,
 1200    show_gutter: bool,
 1201    show_line_numbers: Option<bool>,
 1202    show_git_diff_gutter: Option<bool>,
 1203    show_code_actions: Option<bool>,
 1204    show_runnables: Option<bool>,
 1205    show_breakpoints: Option<bool>,
 1206    git_blame_gutter_max_author_length: Option<usize>,
 1207    pub display_snapshot: DisplaySnapshot,
 1208    pub placeholder_text: Option<Arc<str>>,
 1209    is_focused: bool,
 1210    scroll_anchor: ScrollAnchor,
 1211    ongoing_scroll: OngoingScroll,
 1212    current_line_highlight: CurrentLineHighlight,
 1213    gutter_hovered: bool,
 1214}
 1215
 1216#[derive(Default, Debug, Clone, Copy)]
 1217pub struct GutterDimensions {
 1218    pub left_padding: Pixels,
 1219    pub right_padding: Pixels,
 1220    pub width: Pixels,
 1221    pub margin: Pixels,
 1222    pub git_blame_entries_width: Option<Pixels>,
 1223}
 1224
 1225impl GutterDimensions {
 1226    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1227        Self {
 1228            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1229            ..Default::default()
 1230        }
 1231    }
 1232
 1233    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1234        -cx.text_system().descent(font_id, font_size)
 1235    }
 1236    /// The full width of the space taken up by the gutter.
 1237    pub fn full_width(&self) -> Pixels {
 1238        self.margin + self.width
 1239    }
 1240
 1241    /// The width of the space reserved for the fold indicators,
 1242    /// use alongside 'justify_end' and `gutter_width` to
 1243    /// right align content with the line numbers
 1244    pub fn fold_area_width(&self) -> Pixels {
 1245        self.margin + self.right_padding
 1246    }
 1247}
 1248
 1249struct CharacterDimensions {
 1250    em_width: Pixels,
 1251    em_advance: Pixels,
 1252    line_height: Pixels,
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct RemoteSelection {
 1257    pub replica_id: ReplicaId,
 1258    pub selection: Selection<Anchor>,
 1259    pub cursor_shape: CursorShape,
 1260    pub collaborator_id: CollaboratorId,
 1261    pub line_mode: bool,
 1262    pub user_name: Option<SharedString>,
 1263    pub color: PlayerColor,
 1264}
 1265
 1266#[derive(Clone, Debug)]
 1267struct SelectionHistoryEntry {
 1268    selections: Arc<[Selection<Anchor>]>,
 1269    select_next_state: Option<SelectNextState>,
 1270    select_prev_state: Option<SelectNextState>,
 1271    add_selections_state: Option<AddSelectionsState>,
 1272}
 1273
 1274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1275enum SelectionHistoryMode {
 1276    Normal,
 1277    Undoing,
 1278    Redoing,
 1279    Skipping,
 1280}
 1281
 1282#[derive(Clone, PartialEq, Eq, Hash)]
 1283struct HoveredCursor {
 1284    replica_id: u16,
 1285    selection_id: usize,
 1286}
 1287
 1288impl Default for SelectionHistoryMode {
 1289    fn default() -> Self {
 1290        Self::Normal
 1291    }
 1292}
 1293
 1294#[derive(Debug)]
 1295/// SelectionEffects controls the side-effects of updating the selection.
 1296///
 1297/// The default behaviour does "what you mostly want":
 1298/// - it pushes to the nav history if the cursor moved by >10 lines
 1299/// - it re-triggers completion requests
 1300/// - it scrolls to fit
 1301///
 1302/// You might want to modify these behaviours. For example when doing a "jump"
 1303/// like go to definition, we always want to add to nav history; but when scrolling
 1304/// in vim mode we never do.
 1305///
 1306/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1307/// move.
 1308#[derive(Clone)]
 1309pub struct SelectionEffects {
 1310    nav_history: Option<bool>,
 1311    completions: bool,
 1312    scroll: Option<Autoscroll>,
 1313}
 1314
 1315impl Default for SelectionEffects {
 1316    fn default() -> Self {
 1317        Self {
 1318            nav_history: None,
 1319            completions: true,
 1320            scroll: Some(Autoscroll::fit()),
 1321        }
 1322    }
 1323}
 1324impl SelectionEffects {
 1325    pub fn scroll(scroll: Autoscroll) -> Self {
 1326        Self {
 1327            scroll: Some(scroll),
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn no_scroll() -> Self {
 1333        Self {
 1334            scroll: None,
 1335            ..Default::default()
 1336        }
 1337    }
 1338
 1339    pub fn completions(self, completions: bool) -> Self {
 1340        Self {
 1341            completions,
 1342            ..self
 1343        }
 1344    }
 1345
 1346    pub fn nav_history(self, nav_history: bool) -> Self {
 1347        Self {
 1348            nav_history: Some(nav_history),
 1349            ..self
 1350        }
 1351    }
 1352}
 1353
 1354struct DeferredSelectionEffectsState {
 1355    changed: bool,
 1356    effects: SelectionEffects,
 1357    old_cursor_position: Anchor,
 1358    history_entry: SelectionHistoryEntry,
 1359}
 1360
 1361#[derive(Default)]
 1362struct SelectionHistory {
 1363    #[allow(clippy::type_complexity)]
 1364    selections_by_transaction:
 1365        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1366    mode: SelectionHistoryMode,
 1367    undo_stack: VecDeque<SelectionHistoryEntry>,
 1368    redo_stack: VecDeque<SelectionHistoryEntry>,
 1369}
 1370
 1371impl SelectionHistory {
 1372    #[track_caller]
 1373    fn insert_transaction(
 1374        &mut self,
 1375        transaction_id: TransactionId,
 1376        selections: Arc<[Selection<Anchor>]>,
 1377    ) {
 1378        if selections.is_empty() {
 1379            log::error!(
 1380                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1381                std::panic::Location::caller()
 1382            );
 1383            return;
 1384        }
 1385        self.selections_by_transaction
 1386            .insert(transaction_id, (selections, None));
 1387    }
 1388
 1389    #[allow(clippy::type_complexity)]
 1390    fn transaction(
 1391        &self,
 1392        transaction_id: TransactionId,
 1393    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1394        self.selections_by_transaction.get(&transaction_id)
 1395    }
 1396
 1397    #[allow(clippy::type_complexity)]
 1398    fn transaction_mut(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1402        self.selections_by_transaction.get_mut(&transaction_id)
 1403    }
 1404
 1405    fn push(&mut self, entry: SelectionHistoryEntry) {
 1406        if !entry.selections.is_empty() {
 1407            match self.mode {
 1408                SelectionHistoryMode::Normal => {
 1409                    self.push_undo(entry);
 1410                    self.redo_stack.clear();
 1411                }
 1412                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1413                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1414                SelectionHistoryMode::Skipping => {}
 1415            }
 1416        }
 1417    }
 1418
 1419    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1420        if self
 1421            .undo_stack
 1422            .back()
 1423            .map_or(true, |e| e.selections != entry.selections)
 1424        {
 1425            self.undo_stack.push_back(entry);
 1426            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1427                self.undo_stack.pop_front();
 1428            }
 1429        }
 1430    }
 1431
 1432    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1433        if self
 1434            .redo_stack
 1435            .back()
 1436            .map_or(true, |e| e.selections != entry.selections)
 1437        {
 1438            self.redo_stack.push_back(entry);
 1439            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1440                self.redo_stack.pop_front();
 1441            }
 1442        }
 1443    }
 1444}
 1445
 1446#[derive(Clone, Copy)]
 1447pub struct RowHighlightOptions {
 1448    pub autoscroll: bool,
 1449    pub include_gutter: bool,
 1450}
 1451
 1452impl Default for RowHighlightOptions {
 1453    fn default() -> Self {
 1454        Self {
 1455            autoscroll: Default::default(),
 1456            include_gutter: true,
 1457        }
 1458    }
 1459}
 1460
 1461struct RowHighlight {
 1462    index: usize,
 1463    range: Range<Anchor>,
 1464    color: Hsla,
 1465    options: RowHighlightOptions,
 1466    type_id: TypeId,
 1467}
 1468
 1469#[derive(Clone, Debug)]
 1470struct AddSelectionsState {
 1471    groups: Vec<AddSelectionsGroup>,
 1472}
 1473
 1474#[derive(Clone, Debug)]
 1475struct AddSelectionsGroup {
 1476    above: bool,
 1477    stack: Vec<usize>,
 1478}
 1479
 1480#[derive(Clone)]
 1481struct SelectNextState {
 1482    query: AhoCorasick,
 1483    wordwise: bool,
 1484    done: bool,
 1485}
 1486
 1487impl std::fmt::Debug for SelectNextState {
 1488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1489        f.debug_struct(std::any::type_name::<Self>())
 1490            .field("wordwise", &self.wordwise)
 1491            .field("done", &self.done)
 1492            .finish()
 1493    }
 1494}
 1495
 1496#[derive(Debug)]
 1497struct AutocloseRegion {
 1498    selection_id: usize,
 1499    range: Range<Anchor>,
 1500    pair: BracketPair,
 1501}
 1502
 1503#[derive(Debug)]
 1504struct SnippetState {
 1505    ranges: Vec<Vec<Range<Anchor>>>,
 1506    active_index: usize,
 1507    choices: Vec<Option<Vec<String>>>,
 1508}
 1509
 1510#[doc(hidden)]
 1511pub struct RenameState {
 1512    pub range: Range<Anchor>,
 1513    pub old_name: Arc<str>,
 1514    pub editor: Entity<Editor>,
 1515    block_id: CustomBlockId,
 1516}
 1517
 1518struct InvalidationStack<T>(Vec<T>);
 1519
 1520struct RegisteredInlineCompletionProvider {
 1521    provider: Arc<dyn InlineCompletionProviderHandle>,
 1522    _subscription: Subscription,
 1523}
 1524
 1525#[derive(Debug, PartialEq, Eq)]
 1526pub struct ActiveDiagnosticGroup {
 1527    pub active_range: Range<Anchor>,
 1528    pub active_message: String,
 1529    pub group_id: usize,
 1530    pub blocks: HashSet<CustomBlockId>,
 1531}
 1532
 1533#[derive(Debug, PartialEq, Eq)]
 1534
 1535pub(crate) enum ActiveDiagnostic {
 1536    None,
 1537    All,
 1538    Group(ActiveDiagnosticGroup),
 1539}
 1540
 1541#[derive(Serialize, Deserialize, Clone, Debug)]
 1542pub struct ClipboardSelection {
 1543    /// The number of bytes in this selection.
 1544    pub len: usize,
 1545    /// Whether this was a full-line selection.
 1546    pub is_entire_line: bool,
 1547    /// The indentation of the first line when this content was originally copied.
 1548    pub first_line_indent: u32,
 1549}
 1550
 1551// selections, scroll behavior, was newest selection reversed
 1552type SelectSyntaxNodeHistoryState = (
 1553    Box<[Selection<usize>]>,
 1554    SelectSyntaxNodeScrollBehavior,
 1555    bool,
 1556);
 1557
 1558#[derive(Default)]
 1559struct SelectSyntaxNodeHistory {
 1560    stack: Vec<SelectSyntaxNodeHistoryState>,
 1561    // disable temporarily to allow changing selections without losing the stack
 1562    pub disable_clearing: bool,
 1563}
 1564
 1565impl SelectSyntaxNodeHistory {
 1566    pub fn try_clear(&mut self) {
 1567        if !self.disable_clearing {
 1568            self.stack.clear();
 1569        }
 1570    }
 1571
 1572    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1573        self.stack.push(selection);
 1574    }
 1575
 1576    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1577        self.stack.pop()
 1578    }
 1579}
 1580
 1581enum SelectSyntaxNodeScrollBehavior {
 1582    CursorTop,
 1583    FitSelection,
 1584    CursorBottom,
 1585}
 1586
 1587#[derive(Debug)]
 1588pub(crate) struct NavigationData {
 1589    cursor_anchor: Anchor,
 1590    cursor_position: Point,
 1591    scroll_anchor: ScrollAnchor,
 1592    scroll_top_row: u32,
 1593}
 1594
 1595#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1596pub enum GotoDefinitionKind {
 1597    Symbol,
 1598    Declaration,
 1599    Type,
 1600    Implementation,
 1601}
 1602
 1603#[derive(Debug, Clone)]
 1604enum InlayHintRefreshReason {
 1605    ModifiersChanged(bool),
 1606    Toggle(bool),
 1607    SettingsChange(InlayHintSettings),
 1608    NewLinesShown,
 1609    BufferEdited(HashSet<Arc<Language>>),
 1610    RefreshRequested,
 1611    ExcerptsRemoved(Vec<ExcerptId>),
 1612}
 1613
 1614impl InlayHintRefreshReason {
 1615    fn description(&self) -> &'static str {
 1616        match self {
 1617            Self::ModifiersChanged(_) => "modifiers changed",
 1618            Self::Toggle(_) => "toggle",
 1619            Self::SettingsChange(_) => "settings change",
 1620            Self::NewLinesShown => "new lines shown",
 1621            Self::BufferEdited(_) => "buffer edited",
 1622            Self::RefreshRequested => "refresh requested",
 1623            Self::ExcerptsRemoved(_) => "excerpts removed",
 1624        }
 1625    }
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    fn new_internal(
 1769        mode: EditorMode,
 1770        buffer: Entity<MultiBuffer>,
 1771        project: Option<Entity<Project>>,
 1772        display_map: Option<Entity<DisplayMap>>,
 1773        window: &mut Window,
 1774        cx: &mut Context<Self>,
 1775    ) -> Self {
 1776        debug_assert!(
 1777            display_map.is_none() || mode.is_minimap(),
 1778            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1779        );
 1780
 1781        let full_mode = mode.is_full();
 1782        let is_minimap = mode.is_minimap();
 1783        let diagnostics_max_severity = if full_mode {
 1784            EditorSettings::get_global(cx)
 1785                .diagnostics_max_severity
 1786                .unwrap_or(DiagnosticSeverity::Hint)
 1787        } else {
 1788            DiagnosticSeverity::Off
 1789        };
 1790        let style = window.text_style();
 1791        let font_size = style.font_size.to_pixels(window.rem_size());
 1792        let editor = cx.entity().downgrade();
 1793        let fold_placeholder = FoldPlaceholder {
 1794            constrain_width: true,
 1795            render: Arc::new(move |fold_id, fold_range, cx| {
 1796                let editor = editor.clone();
 1797                div()
 1798                    .id(fold_id)
 1799                    .bg(cx.theme().colors().ghost_element_background)
 1800                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1801                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1802                    .rounded_xs()
 1803                    .size_full()
 1804                    .cursor_pointer()
 1805                    .child("")
 1806                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1807                    .on_click(move |_, _window, cx| {
 1808                        editor
 1809                            .update(cx, |editor, cx| {
 1810                                editor.unfold_ranges(
 1811                                    &[fold_range.start..fold_range.end],
 1812                                    true,
 1813                                    false,
 1814                                    cx,
 1815                                );
 1816                                cx.stop_propagation();
 1817                            })
 1818                            .ok();
 1819                    })
 1820                    .into_any()
 1821            }),
 1822            merge_adjacent: true,
 1823            ..FoldPlaceholder::default()
 1824        };
 1825        let display_map = display_map.unwrap_or_else(|| {
 1826            cx.new(|cx| {
 1827                DisplayMap::new(
 1828                    buffer.clone(),
 1829                    style.font(),
 1830                    font_size,
 1831                    None,
 1832                    FILE_HEADER_HEIGHT,
 1833                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1834                    fold_placeholder,
 1835                    diagnostics_max_severity,
 1836                    cx,
 1837                )
 1838            })
 1839        });
 1840
 1841        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1842
 1843        let blink_manager = cx.new(|cx| {
 1844            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1845            if is_minimap {
 1846                blink_manager.disable(cx);
 1847            }
 1848            blink_manager
 1849        });
 1850
 1851        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1852            .then(|| language_settings::SoftWrap::None);
 1853
 1854        let mut project_subscriptions = Vec::new();
 1855        if full_mode {
 1856            if let Some(project) = project.as_ref() {
 1857                project_subscriptions.push(cx.subscribe_in(
 1858                    project,
 1859                    window,
 1860                    |editor, _, event, window, cx| match event {
 1861                        project::Event::RefreshCodeLens => {
 1862                            // we always query lens with actions, without storing them, always refreshing them
 1863                        }
 1864                        project::Event::RefreshInlayHints => {
 1865                            editor
 1866                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1867                        }
 1868                        project::Event::LanguageServerAdded(..)
 1869                        | project::Event::LanguageServerRemoved(..) => {
 1870                            if editor.tasks_update_task.is_none() {
 1871                                editor.tasks_update_task =
 1872                                    Some(editor.refresh_runnables(window, cx));
 1873                            }
 1874                            editor.update_lsp_data(true, None, window, cx);
 1875                        }
 1876                        project::Event::SnippetEdit(id, snippet_edits) => {
 1877                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                                let focus_handle = editor.focus_handle(cx);
 1879                                if focus_handle.is_focused(window) {
 1880                                    let snapshot = buffer.read(cx).snapshot();
 1881                                    for (range, snippet) in snippet_edits {
 1882                                        let editor_range =
 1883                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                        editor
 1885                                            .insert_snippet(
 1886                                                &[editor_range],
 1887                                                snippet.clone(),
 1888                                                window,
 1889                                                cx,
 1890                                            )
 1891                                            .ok();
 1892                                    }
 1893                                }
 1894                            }
 1895                        }
 1896                        _ => {}
 1897                    },
 1898                ));
 1899                if let Some(task_inventory) = project
 1900                    .read(cx)
 1901                    .task_store()
 1902                    .read(cx)
 1903                    .task_inventory()
 1904                    .cloned()
 1905                {
 1906                    project_subscriptions.push(cx.observe_in(
 1907                        &task_inventory,
 1908                        window,
 1909                        |editor, _, window, cx| {
 1910                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1911                        },
 1912                    ));
 1913                };
 1914
 1915                project_subscriptions.push(cx.subscribe_in(
 1916                    &project.read(cx).breakpoint_store(),
 1917                    window,
 1918                    |editor, _, event, window, cx| match event {
 1919                        BreakpointStoreEvent::ClearDebugLines => {
 1920                            editor.clear_row_highlights::<ActiveDebugLine>();
 1921                            editor.refresh_inline_values(cx);
 1922                        }
 1923                        BreakpointStoreEvent::SetDebugLine => {
 1924                            if editor.go_to_active_debug_line(window, cx) {
 1925                                cx.stop_propagation();
 1926                            }
 1927
 1928                            editor.refresh_inline_values(cx);
 1929                        }
 1930                        _ => {}
 1931                    },
 1932                ));
 1933                let git_store = project.read(cx).git_store().clone();
 1934                let project = project.clone();
 1935                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1936                    match event {
 1937                        GitStoreEvent::RepositoryUpdated(
 1938                            _,
 1939                            RepositoryEvent::Updated {
 1940                                new_instance: true, ..
 1941                            },
 1942                            _,
 1943                        ) => {
 1944                            this.load_diff_task = Some(
 1945                                update_uncommitted_diff_for_buffer(
 1946                                    cx.entity(),
 1947                                    &project,
 1948                                    this.buffer.read(cx).all_buffers(),
 1949                                    this.buffer.clone(),
 1950                                    cx,
 1951                                )
 1952                                .shared(),
 1953                            );
 1954                        }
 1955                        _ => {}
 1956                    }
 1957                }));
 1958            }
 1959        }
 1960
 1961        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1962
 1963        let inlay_hint_settings =
 1964            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1965        let focus_handle = cx.focus_handle();
 1966        if !is_minimap {
 1967            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1968                .detach();
 1969            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1970                .detach();
 1971            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1972                .detach();
 1973            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1974                .detach();
 1975            cx.observe_pending_input(window, Self::observe_pending_input)
 1976                .detach();
 1977        }
 1978
 1979        let show_indent_guides = if matches!(
 1980            mode,
 1981            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1982        ) {
 1983            Some(false)
 1984        } else {
 1985            None
 1986        };
 1987
 1988        let breakpoint_store = match (&mode, project.as_ref()) {
 1989            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1990            _ => None,
 1991        };
 1992
 1993        let mut code_action_providers = Vec::new();
 1994        let mut load_uncommitted_diff = None;
 1995        if let Some(project) = project.clone() {
 1996            load_uncommitted_diff = Some(
 1997                update_uncommitted_diff_for_buffer(
 1998                    cx.entity(),
 1999                    &project,
 2000                    buffer.read(cx).all_buffers(),
 2001                    buffer.clone(),
 2002                    cx,
 2003                )
 2004                .shared(),
 2005            );
 2006            code_action_providers.push(Rc::new(project) as Rc<_>);
 2007        }
 2008
 2009        let mut editor = Self {
 2010            focus_handle,
 2011            show_cursor_when_unfocused: false,
 2012            last_focused_descendant: None,
 2013            buffer: buffer.clone(),
 2014            display_map: display_map.clone(),
 2015            selections,
 2016            scroll_manager: ScrollManager::new(cx),
 2017            columnar_selection_state: None,
 2018            add_selections_state: None,
 2019            select_next_state: None,
 2020            select_prev_state: None,
 2021            selection_history: SelectionHistory::default(),
 2022            defer_selection_effects: false,
 2023            deferred_selection_effects_state: None,
 2024            autoclose_regions: Vec::new(),
 2025            snippet_stack: InvalidationStack::default(),
 2026            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2027            ime_transaction: None,
 2028            active_diagnostics: ActiveDiagnostic::None,
 2029            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2030            inline_diagnostics_update: Task::ready(()),
 2031            inline_diagnostics: Vec::new(),
 2032            soft_wrap_mode_override,
 2033            diagnostics_max_severity,
 2034            hard_wrap: None,
 2035            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2037            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2038            project,
 2039            blink_manager: blink_manager.clone(),
 2040            show_local_selections: true,
 2041            show_scrollbars: ScrollbarAxes {
 2042                horizontal: full_mode,
 2043                vertical: full_mode,
 2044            },
 2045            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2046            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2047            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2048            show_gutter: full_mode,
 2049            show_line_numbers: (!full_mode).then_some(false),
 2050            use_relative_line_numbers: None,
 2051            disable_expand_excerpt_buttons: !full_mode,
 2052            show_git_diff_gutter: None,
 2053            show_code_actions: None,
 2054            show_runnables: None,
 2055            show_breakpoints: None,
 2056            show_wrap_guides: None,
 2057            show_indent_guides,
 2058            placeholder_text: None,
 2059            highlight_order: 0,
 2060            highlighted_rows: HashMap::default(),
 2061            background_highlights: TreeMap::default(),
 2062            gutter_highlights: TreeMap::default(),
 2063            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2064            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2065            nav_history: None,
 2066            context_menu: RefCell::new(None),
 2067            context_menu_options: None,
 2068            mouse_context_menu: None,
 2069            completion_tasks: Vec::new(),
 2070            inline_blame_popover: None,
 2071            inline_blame_popover_show_task: None,
 2072            signature_help_state: SignatureHelpState::default(),
 2073            auto_signature_help: None,
 2074            find_all_references_task_sources: Vec::new(),
 2075            next_completion_id: 0,
 2076            next_inlay_id: 0,
 2077            code_action_providers,
 2078            available_code_actions: None,
 2079            code_actions_task: None,
 2080            quick_selection_highlight_task: None,
 2081            debounced_selection_highlight_task: None,
 2082            document_highlights_task: None,
 2083            linked_editing_range_task: None,
 2084            pending_rename: None,
 2085            searchable: !is_minimap,
 2086            cursor_shape: EditorSettings::get_global(cx)
 2087                .cursor_shape
 2088                .unwrap_or_default(),
 2089            current_line_highlight: None,
 2090            autoindent_mode: Some(AutoindentMode::EachLine),
 2091            collapse_matches: false,
 2092            workspace: None,
 2093            input_enabled: !is_minimap,
 2094            use_modal_editing: full_mode,
 2095            read_only: is_minimap,
 2096            use_autoclose: true,
 2097            use_auto_surround: true,
 2098            auto_replace_emoji_shortcode: false,
 2099            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2100            leader_id: None,
 2101            remote_id: None,
 2102            hover_state: HoverState::default(),
 2103            pending_mouse_down: None,
 2104            hovered_link_state: None,
 2105            edit_prediction_provider: None,
 2106            active_inline_completion: None,
 2107            stale_inline_completion_in_menu: None,
 2108            edit_prediction_preview: EditPredictionPreview::Inactive {
 2109                released_too_fast: false,
 2110            },
 2111            inline_diagnostics_enabled: full_mode,
 2112            diagnostics_enabled: full_mode,
 2113            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2114            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2115            gutter_hovered: false,
 2116            pixel_position_of_newest_cursor: None,
 2117            last_bounds: None,
 2118            last_position_map: None,
 2119            expect_bounds_change: None,
 2120            gutter_dimensions: GutterDimensions::default(),
 2121            style: None,
 2122            show_cursor_names: false,
 2123            hovered_cursors: HashMap::default(),
 2124            next_editor_action_id: EditorActionId::default(),
 2125            editor_actions: Rc::default(),
 2126            inline_completions_hidden_for_vim_mode: false,
 2127            show_inline_completions_override: None,
 2128            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2129            edit_prediction_settings: EditPredictionSettings::Disabled,
 2130            edit_prediction_indent_conflict: false,
 2131            edit_prediction_requires_modifier_in_indent_conflict: true,
 2132            custom_context_menu: None,
 2133            show_git_blame_gutter: false,
 2134            show_git_blame_inline: false,
 2135            show_selection_menu: None,
 2136            show_git_blame_inline_delay_task: None,
 2137            git_blame_inline_enabled: full_mode
 2138                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2139            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2140            serialize_dirty_buffers: !is_minimap
 2141                && ProjectSettings::get_global(cx)
 2142                    .session
 2143                    .restore_unsaved_buffers,
 2144            blame: None,
 2145            blame_subscription: None,
 2146            tasks: BTreeMap::default(),
 2147
 2148            breakpoint_store,
 2149            gutter_breakpoint_indicator: (None, None),
 2150            hovered_diff_hunk_row: None,
 2151            _subscriptions: (!is_minimap)
 2152                .then(|| {
 2153                    vec![
 2154                        cx.observe(&buffer, Self::on_buffer_changed),
 2155                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2156                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2157                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2158                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2159                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2160                        cx.observe_window_activation(window, |editor, window, cx| {
 2161                            let active = window.is_window_active();
 2162                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2163                                if active {
 2164                                    blink_manager.enable(cx);
 2165                                } else {
 2166                                    blink_manager.disable(cx);
 2167                                }
 2168                            });
 2169                            if active {
 2170                                editor.show_mouse_cursor(cx);
 2171                            }
 2172                        }),
 2173                    ]
 2174                })
 2175                .unwrap_or_default(),
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206
 2207        if is_minimap {
 2208            return editor;
 2209        }
 2210
 2211        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2212            editor
 2213                ._subscriptions
 2214                .push(cx.observe(breakpoints, |_, _, cx| {
 2215                    cx.notify();
 2216                }));
 2217        }
 2218        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2219        editor._subscriptions.extend(project_subscriptions);
 2220
 2221        editor._subscriptions.push(cx.subscribe_in(
 2222            &cx.entity(),
 2223            window,
 2224            |editor, _, e: &EditorEvent, window, cx| match e {
 2225                EditorEvent::ScrollPositionChanged { local, .. } => {
 2226                    if *local {
 2227                        let new_anchor = editor.scroll_manager.anchor();
 2228                        let snapshot = editor.snapshot(window, cx);
 2229                        editor.update_restoration_data(cx, move |data| {
 2230                            data.scroll_position = (
 2231                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2232                                new_anchor.offset,
 2233                            );
 2234                        });
 2235                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2236                        editor.inline_blame_popover.take();
 2237                    }
 2238                }
 2239                EditorEvent::Edited { .. } => {
 2240                    if !vim_enabled(cx) {
 2241                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2242                        let pop_state = editor
 2243                            .change_list
 2244                            .last()
 2245                            .map(|previous| {
 2246                                previous.len() == selections.len()
 2247                                    && previous.iter().enumerate().all(|(ix, p)| {
 2248                                        p.to_display_point(&map).row()
 2249                                            == selections[ix].head().row()
 2250                                    })
 2251                            })
 2252                            .unwrap_or(false);
 2253                        let new_positions = selections
 2254                            .into_iter()
 2255                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2256                            .collect();
 2257                        editor
 2258                            .change_list
 2259                            .push_to_change_list(pop_state, new_positions);
 2260                    }
 2261                }
 2262                _ => (),
 2263            },
 2264        ));
 2265
 2266        if let Some(dap_store) = editor
 2267            .project
 2268            .as_ref()
 2269            .map(|project| project.read(cx).dap_store())
 2270        {
 2271            let weak_editor = cx.weak_entity();
 2272
 2273            editor
 2274                ._subscriptions
 2275                .push(
 2276                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2277                        let session_entity = cx.entity();
 2278                        weak_editor
 2279                            .update(cx, |editor, cx| {
 2280                                editor._subscriptions.push(
 2281                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2282                                );
 2283                            })
 2284                            .ok();
 2285                    }),
 2286                );
 2287
 2288            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2289                editor
 2290                    ._subscriptions
 2291                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2292            }
 2293        }
 2294
 2295        // skip adding the initial selection to selection history
 2296        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2297        editor.end_selection(window, cx);
 2298        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2299
 2300        editor.scroll_manager.show_scrollbars(window, cx);
 2301        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2302
 2303        if full_mode {
 2304            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2305            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2306
 2307            if editor.git_blame_inline_enabled {
 2308                editor.start_git_blame_inline(false, window, cx);
 2309            }
 2310
 2311            editor.go_to_active_debug_line(window, cx);
 2312
 2313            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2314                if let Some(project) = editor.project.as_ref() {
 2315                    let handle = project.update(cx, |project, cx| {
 2316                        project.register_buffer_with_language_servers(&buffer, cx)
 2317                    });
 2318                    editor
 2319                        .registered_buffers
 2320                        .insert(buffer.read(cx).remote_id(), handle);
 2321                }
 2322            }
 2323
 2324            editor.minimap =
 2325                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2326            editor.colors = Some(LspColorData::new(cx));
 2327            editor.update_lsp_data(false, None, window, cx);
 2328        }
 2329
 2330        if editor.mode.is_full() {
 2331            editor.report_editor_event("Editor Opened", None, cx);
 2332        }
 2333
 2334        editor
 2335    }
 2336
 2337    pub fn deploy_mouse_context_menu(
 2338        &mut self,
 2339        position: gpui::Point<Pixels>,
 2340        context_menu: Entity<ContextMenu>,
 2341        window: &mut Window,
 2342        cx: &mut Context<Self>,
 2343    ) {
 2344        self.mouse_context_menu = Some(MouseContextMenu::new(
 2345            self,
 2346            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2347            context_menu,
 2348            window,
 2349            cx,
 2350        ));
 2351    }
 2352
 2353    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2354        self.mouse_context_menu
 2355            .as_ref()
 2356            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2357    }
 2358
 2359    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2360        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2361    }
 2362
 2363    fn key_context_internal(
 2364        &self,
 2365        has_active_edit_prediction: bool,
 2366        window: &Window,
 2367        cx: &App,
 2368    ) -> KeyContext {
 2369        let mut key_context = KeyContext::new_with_defaults();
 2370        key_context.add("Editor");
 2371        let mode = match self.mode {
 2372            EditorMode::SingleLine { .. } => "single_line",
 2373            EditorMode::AutoHeight { .. } => "auto_height",
 2374            EditorMode::Minimap { .. } => "minimap",
 2375            EditorMode::Full { .. } => "full",
 2376        };
 2377
 2378        if EditorSettings::jupyter_enabled(cx) {
 2379            key_context.add("jupyter");
 2380        }
 2381
 2382        key_context.set("mode", mode);
 2383        if self.pending_rename.is_some() {
 2384            key_context.add("renaming");
 2385        }
 2386
 2387        match self.context_menu.borrow().as_ref() {
 2388            Some(CodeContextMenu::Completions(menu)) => {
 2389                if menu.visible() {
 2390                    key_context.add("menu");
 2391                    key_context.add("showing_completions");
 2392                }
 2393            }
 2394            Some(CodeContextMenu::CodeActions(menu)) => {
 2395                if menu.visible() {
 2396                    key_context.add("menu");
 2397                    key_context.add("showing_code_actions")
 2398                }
 2399            }
 2400            None => {}
 2401        }
 2402
 2403        if self.signature_help_state.has_multiple_signatures() {
 2404            key_context.add("showing_signature_help");
 2405        }
 2406
 2407        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2408        if !self.focus_handle(cx).contains_focused(window, cx)
 2409            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2410        {
 2411            for addon in self.addons.values() {
 2412                addon.extend_key_context(&mut key_context, cx)
 2413            }
 2414        }
 2415
 2416        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2417            if let Some(extension) = singleton_buffer
 2418                .read(cx)
 2419                .file()
 2420                .and_then(|file| file.path().extension()?.to_str())
 2421            {
 2422                key_context.set("extension", extension.to_string());
 2423            }
 2424        } else {
 2425            key_context.add("multibuffer");
 2426        }
 2427
 2428        if has_active_edit_prediction {
 2429            if self.edit_prediction_in_conflict() {
 2430                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2431            } else {
 2432                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2433                key_context.add("copilot_suggestion");
 2434            }
 2435        }
 2436
 2437        if self.selection_mark_mode {
 2438            key_context.add("selection_mode");
 2439        }
 2440
 2441        key_context
 2442    }
 2443
 2444    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2445        if self.mouse_cursor_hidden {
 2446            self.mouse_cursor_hidden = false;
 2447            cx.notify();
 2448        }
 2449    }
 2450
 2451    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2452        let hide_mouse_cursor = match origin {
 2453            HideMouseCursorOrigin::TypingAction => {
 2454                matches!(
 2455                    self.hide_mouse_mode,
 2456                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2457                )
 2458            }
 2459            HideMouseCursorOrigin::MovementAction => {
 2460                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2461            }
 2462        };
 2463        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2464            self.mouse_cursor_hidden = hide_mouse_cursor;
 2465            cx.notify();
 2466        }
 2467    }
 2468
 2469    pub fn edit_prediction_in_conflict(&self) -> bool {
 2470        if !self.show_edit_predictions_in_menu() {
 2471            return false;
 2472        }
 2473
 2474        let showing_completions = self
 2475            .context_menu
 2476            .borrow()
 2477            .as_ref()
 2478            .map_or(false, |context| {
 2479                matches!(context, CodeContextMenu::Completions(_))
 2480            });
 2481
 2482        showing_completions
 2483            || self.edit_prediction_requires_modifier()
 2484            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2485            // bindings to insert tab characters.
 2486            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2487    }
 2488
 2489    pub fn accept_edit_prediction_keybind(
 2490        &self,
 2491        accept_partial: bool,
 2492        window: &Window,
 2493        cx: &App,
 2494    ) -> AcceptEditPredictionBinding {
 2495        let key_context = self.key_context_internal(true, window, cx);
 2496        let in_conflict = self.edit_prediction_in_conflict();
 2497
 2498        let bindings = if accept_partial {
 2499            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2500        } else {
 2501            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2502        };
 2503
 2504        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2505        // just the first one.
 2506        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2507            !in_conflict
 2508                || binding
 2509                    .keystrokes()
 2510                    .first()
 2511                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2512        }))
 2513    }
 2514
 2515    pub fn new_file(
 2516        workspace: &mut Workspace,
 2517        _: &workspace::NewFile,
 2518        window: &mut Window,
 2519        cx: &mut Context<Workspace>,
 2520    ) {
 2521        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2522            "Failed to create buffer",
 2523            window,
 2524            cx,
 2525            |e, _, _| match e.error_code() {
 2526                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2527                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2528                e.error_tag("required").unwrap_or("the latest version")
 2529            )),
 2530                _ => None,
 2531            },
 2532        );
 2533    }
 2534
 2535    pub fn new_in_workspace(
 2536        workspace: &mut Workspace,
 2537        window: &mut Window,
 2538        cx: &mut Context<Workspace>,
 2539    ) -> Task<Result<Entity<Editor>>> {
 2540        let project = workspace.project().clone();
 2541        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2542
 2543        cx.spawn_in(window, async move |workspace, cx| {
 2544            let buffer = create.await?;
 2545            workspace.update_in(cx, |workspace, window, cx| {
 2546                let editor =
 2547                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2548                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2549                editor
 2550            })
 2551        })
 2552    }
 2553
 2554    fn new_file_vertical(
 2555        workspace: &mut Workspace,
 2556        _: &workspace::NewFileSplitVertical,
 2557        window: &mut Window,
 2558        cx: &mut Context<Workspace>,
 2559    ) {
 2560        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2561    }
 2562
 2563    fn new_file_horizontal(
 2564        workspace: &mut Workspace,
 2565        _: &workspace::NewFileSplitHorizontal,
 2566        window: &mut Window,
 2567        cx: &mut Context<Workspace>,
 2568    ) {
 2569        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2570    }
 2571
 2572    fn new_file_in_direction(
 2573        workspace: &mut Workspace,
 2574        direction: SplitDirection,
 2575        window: &mut Window,
 2576        cx: &mut Context<Workspace>,
 2577    ) {
 2578        let project = workspace.project().clone();
 2579        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2580
 2581        cx.spawn_in(window, async move |workspace, cx| {
 2582            let buffer = create.await?;
 2583            workspace.update_in(cx, move |workspace, window, cx| {
 2584                workspace.split_item(
 2585                    direction,
 2586                    Box::new(
 2587                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2588                    ),
 2589                    window,
 2590                    cx,
 2591                )
 2592            })?;
 2593            anyhow::Ok(())
 2594        })
 2595        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2596            match e.error_code() {
 2597                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2598                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2599                e.error_tag("required").unwrap_or("the latest version")
 2600            )),
 2601                _ => None,
 2602            }
 2603        });
 2604    }
 2605
 2606    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2607        self.leader_id
 2608    }
 2609
 2610    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2611        &self.buffer
 2612    }
 2613
 2614    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2615        self.workspace.as_ref()?.0.upgrade()
 2616    }
 2617
 2618    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2619        self.buffer().read(cx).title(cx)
 2620    }
 2621
 2622    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2623        let git_blame_gutter_max_author_length = self
 2624            .render_git_blame_gutter(cx)
 2625            .then(|| {
 2626                if let Some(blame) = self.blame.as_ref() {
 2627                    let max_author_length =
 2628                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2629                    Some(max_author_length)
 2630                } else {
 2631                    None
 2632                }
 2633            })
 2634            .flatten();
 2635
 2636        EditorSnapshot {
 2637            mode: self.mode.clone(),
 2638            show_gutter: self.show_gutter,
 2639            show_line_numbers: self.show_line_numbers,
 2640            show_git_diff_gutter: self.show_git_diff_gutter,
 2641            show_code_actions: self.show_code_actions,
 2642            show_runnables: self.show_runnables,
 2643            show_breakpoints: self.show_breakpoints,
 2644            git_blame_gutter_max_author_length,
 2645            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2646            scroll_anchor: self.scroll_manager.anchor(),
 2647            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2648            placeholder_text: self.placeholder_text.clone(),
 2649            is_focused: self.focus_handle.is_focused(window),
 2650            current_line_highlight: self
 2651                .current_line_highlight
 2652                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2653            gutter_hovered: self.gutter_hovered,
 2654        }
 2655    }
 2656
 2657    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2658        self.buffer.read(cx).language_at(point, cx)
 2659    }
 2660
 2661    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2662        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2663    }
 2664
 2665    pub fn active_excerpt(
 2666        &self,
 2667        cx: &App,
 2668    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2669        self.buffer
 2670            .read(cx)
 2671            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2672    }
 2673
 2674    pub fn mode(&self) -> &EditorMode {
 2675        &self.mode
 2676    }
 2677
 2678    pub fn set_mode(&mut self, mode: EditorMode) {
 2679        self.mode = mode;
 2680    }
 2681
 2682    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2683        self.collaboration_hub.as_deref()
 2684    }
 2685
 2686    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2687        self.collaboration_hub = Some(hub);
 2688    }
 2689
 2690    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2691        self.in_project_search = in_project_search;
 2692    }
 2693
 2694    pub fn set_custom_context_menu(
 2695        &mut self,
 2696        f: impl 'static
 2697        + Fn(
 2698            &mut Self,
 2699            DisplayPoint,
 2700            &mut Window,
 2701            &mut Context<Self>,
 2702        ) -> Option<Entity<ui::ContextMenu>>,
 2703    ) {
 2704        self.custom_context_menu = Some(Box::new(f))
 2705    }
 2706
 2707    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2708        self.completion_provider = provider;
 2709    }
 2710
 2711    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2712        self.semantics_provider.clone()
 2713    }
 2714
 2715    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2716        self.semantics_provider = provider;
 2717    }
 2718
 2719    pub fn set_edit_prediction_provider<T>(
 2720        &mut self,
 2721        provider: Option<Entity<T>>,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) where
 2725        T: EditPredictionProvider,
 2726    {
 2727        self.edit_prediction_provider =
 2728            provider.map(|provider| RegisteredInlineCompletionProvider {
 2729                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2730                    if this.focus_handle.is_focused(window) {
 2731                        this.update_visible_inline_completion(window, cx);
 2732                    }
 2733                }),
 2734                provider: Arc::new(provider),
 2735            });
 2736        self.update_edit_prediction_settings(cx);
 2737        self.refresh_inline_completion(false, false, window, cx);
 2738    }
 2739
 2740    pub fn placeholder_text(&self) -> Option<&str> {
 2741        self.placeholder_text.as_deref()
 2742    }
 2743
 2744    pub fn set_placeholder_text(
 2745        &mut self,
 2746        placeholder_text: impl Into<Arc<str>>,
 2747        cx: &mut Context<Self>,
 2748    ) {
 2749        let placeholder_text = Some(placeholder_text.into());
 2750        if self.placeholder_text != placeholder_text {
 2751            self.placeholder_text = placeholder_text;
 2752            cx.notify();
 2753        }
 2754    }
 2755
 2756    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2757        self.cursor_shape = cursor_shape;
 2758
 2759        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2760        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2761
 2762        cx.notify();
 2763    }
 2764
 2765    pub fn set_current_line_highlight(
 2766        &mut self,
 2767        current_line_highlight: Option<CurrentLineHighlight>,
 2768    ) {
 2769        self.current_line_highlight = current_line_highlight;
 2770    }
 2771
 2772    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2773        self.collapse_matches = collapse_matches;
 2774    }
 2775
 2776    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2777        let buffers = self.buffer.read(cx).all_buffers();
 2778        let Some(project) = self.project.as_ref() else {
 2779            return;
 2780        };
 2781        project.update(cx, |project, cx| {
 2782            for buffer in buffers {
 2783                self.registered_buffers
 2784                    .entry(buffer.read(cx).remote_id())
 2785                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2786            }
 2787        })
 2788    }
 2789
 2790    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2791        if self.collapse_matches {
 2792            return range.start..range.start;
 2793        }
 2794        range.clone()
 2795    }
 2796
 2797    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2798        if self.display_map.read(cx).clip_at_line_ends != clip {
 2799            self.display_map
 2800                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2801        }
 2802    }
 2803
 2804    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2805        self.input_enabled = input_enabled;
 2806    }
 2807
 2808    pub fn set_inline_completions_hidden_for_vim_mode(
 2809        &mut self,
 2810        hidden: bool,
 2811        window: &mut Window,
 2812        cx: &mut Context<Self>,
 2813    ) {
 2814        if hidden != self.inline_completions_hidden_for_vim_mode {
 2815            self.inline_completions_hidden_for_vim_mode = hidden;
 2816            if hidden {
 2817                self.update_visible_inline_completion(window, cx);
 2818            } else {
 2819                self.refresh_inline_completion(true, false, window, cx);
 2820            }
 2821        }
 2822    }
 2823
 2824    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2825        self.menu_inline_completions_policy = value;
 2826    }
 2827
 2828    pub fn set_autoindent(&mut self, autoindent: bool) {
 2829        if autoindent {
 2830            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2831        } else {
 2832            self.autoindent_mode = None;
 2833        }
 2834    }
 2835
 2836    pub fn read_only(&self, cx: &App) -> bool {
 2837        self.read_only || self.buffer.read(cx).read_only()
 2838    }
 2839
 2840    pub fn set_read_only(&mut self, read_only: bool) {
 2841        self.read_only = read_only;
 2842    }
 2843
 2844    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2845        self.use_autoclose = autoclose;
 2846    }
 2847
 2848    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2849        self.use_auto_surround = auto_surround;
 2850    }
 2851
 2852    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2853        self.auto_replace_emoji_shortcode = auto_replace;
 2854    }
 2855
 2856    pub fn toggle_edit_predictions(
 2857        &mut self,
 2858        _: &ToggleEditPrediction,
 2859        window: &mut Window,
 2860        cx: &mut Context<Self>,
 2861    ) {
 2862        if self.show_inline_completions_override.is_some() {
 2863            self.set_show_edit_predictions(None, window, cx);
 2864        } else {
 2865            let show_edit_predictions = !self.edit_predictions_enabled();
 2866            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2867        }
 2868    }
 2869
 2870    pub fn set_show_edit_predictions(
 2871        &mut self,
 2872        show_edit_predictions: Option<bool>,
 2873        window: &mut Window,
 2874        cx: &mut Context<Self>,
 2875    ) {
 2876        self.show_inline_completions_override = show_edit_predictions;
 2877        self.update_edit_prediction_settings(cx);
 2878
 2879        if let Some(false) = show_edit_predictions {
 2880            self.discard_inline_completion(false, cx);
 2881        } else {
 2882            self.refresh_inline_completion(false, true, window, cx);
 2883        }
 2884    }
 2885
 2886    fn inline_completions_disabled_in_scope(
 2887        &self,
 2888        buffer: &Entity<Buffer>,
 2889        buffer_position: language::Anchor,
 2890        cx: &App,
 2891    ) -> bool {
 2892        let snapshot = buffer.read(cx).snapshot();
 2893        let settings = snapshot.settings_at(buffer_position, cx);
 2894
 2895        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2896            return false;
 2897        };
 2898
 2899        scope.override_name().map_or(false, |scope_name| {
 2900            settings
 2901                .edit_predictions_disabled_in
 2902                .iter()
 2903                .any(|s| s == scope_name)
 2904        })
 2905    }
 2906
 2907    pub fn set_use_modal_editing(&mut self, to: bool) {
 2908        self.use_modal_editing = to;
 2909    }
 2910
 2911    pub fn use_modal_editing(&self) -> bool {
 2912        self.use_modal_editing
 2913    }
 2914
 2915    fn selections_did_change(
 2916        &mut self,
 2917        local: bool,
 2918        old_cursor_position: &Anchor,
 2919        effects: SelectionEffects,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        window.invalidate_character_coordinates();
 2924
 2925        // Copy selections to primary selection buffer
 2926        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2927        if local {
 2928            let selections = self.selections.all::<usize>(cx);
 2929            let buffer_handle = self.buffer.read(cx).read(cx);
 2930
 2931            let mut text = String::new();
 2932            for (index, selection) in selections.iter().enumerate() {
 2933                let text_for_selection = buffer_handle
 2934                    .text_for_range(selection.start..selection.end)
 2935                    .collect::<String>();
 2936
 2937                text.push_str(&text_for_selection);
 2938                if index != selections.len() - 1 {
 2939                    text.push('\n');
 2940                }
 2941            }
 2942
 2943            if !text.is_empty() {
 2944                cx.write_to_primary(ClipboardItem::new_string(text));
 2945            }
 2946        }
 2947
 2948        let selection_anchors = self.selections.disjoint_anchors();
 2949
 2950        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2951            self.buffer.update(cx, |buffer, cx| {
 2952                buffer.set_active_selections(
 2953                    &selection_anchors,
 2954                    self.selections.line_mode,
 2955                    self.cursor_shape,
 2956                    cx,
 2957                )
 2958            });
 2959        }
 2960        let display_map = self
 2961            .display_map
 2962            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2963        let buffer = &display_map.buffer_snapshot;
 2964        if self.selections.count() == 1 {
 2965            self.add_selections_state = None;
 2966        }
 2967        self.select_next_state = None;
 2968        self.select_prev_state = None;
 2969        self.select_syntax_node_history.try_clear();
 2970        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2971        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2972        self.take_rename(false, window, cx);
 2973
 2974        let newest_selection = self.selections.newest_anchor();
 2975        let new_cursor_position = newest_selection.head();
 2976        let selection_start = newest_selection.start;
 2977
 2978        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2979            self.push_to_nav_history(
 2980                *old_cursor_position,
 2981                Some(new_cursor_position.to_point(buffer)),
 2982                false,
 2983                effects.nav_history == Some(true),
 2984                cx,
 2985            );
 2986        }
 2987
 2988        if local {
 2989            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2990                if !self.registered_buffers.contains_key(&buffer_id) {
 2991                    if let Some(project) = self.project.as_ref() {
 2992                        project.update(cx, |project, cx| {
 2993                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2994                                return;
 2995                            };
 2996                            self.registered_buffers.insert(
 2997                                buffer_id,
 2998                                project.register_buffer_with_language_servers(&buffer, cx),
 2999                            );
 3000                        })
 3001                    }
 3002                }
 3003            }
 3004
 3005            let mut context_menu = self.context_menu.borrow_mut();
 3006            let completion_menu = match context_menu.as_ref() {
 3007                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3008                Some(CodeContextMenu::CodeActions(_)) => {
 3009                    *context_menu = None;
 3010                    None
 3011                }
 3012                None => None,
 3013            };
 3014            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3015            drop(context_menu);
 3016
 3017            if effects.completions {
 3018                if let Some(completion_position) = completion_position {
 3019                    let start_offset = selection_start.to_offset(buffer);
 3020                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3021                    let continue_showing = if position_matches {
 3022                        if self.snippet_stack.is_empty() {
 3023                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3024                        } else {
 3025                            // Snippet choices can be shown even when the cursor is in whitespace.
 3026                            // Dismissing the menu with actions like backspace is handled by
 3027                            // invalidation regions.
 3028                            true
 3029                        }
 3030                    } else {
 3031                        false
 3032                    };
 3033
 3034                    if continue_showing {
 3035                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3036                    } else {
 3037                        self.hide_context_menu(window, cx);
 3038                    }
 3039                }
 3040            }
 3041
 3042            hide_hover(self, cx);
 3043
 3044            if old_cursor_position.to_display_point(&display_map).row()
 3045                != new_cursor_position.to_display_point(&display_map).row()
 3046            {
 3047                self.available_code_actions.take();
 3048            }
 3049            self.refresh_code_actions(window, cx);
 3050            self.refresh_document_highlights(cx);
 3051            self.refresh_selected_text_highlights(false, window, cx);
 3052            refresh_matching_bracket_highlights(self, window, cx);
 3053            self.update_visible_inline_completion(window, cx);
 3054            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3055            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3056            self.inline_blame_popover.take();
 3057            if self.git_blame_inline_enabled {
 3058                self.start_inline_blame_timer(window, cx);
 3059            }
 3060        }
 3061
 3062        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3063        cx.emit(EditorEvent::SelectionsChanged { local });
 3064
 3065        let selections = &self.selections.disjoint;
 3066        if selections.len() == 1 {
 3067            cx.emit(SearchEvent::ActiveMatchChanged)
 3068        }
 3069        if local {
 3070            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3071                let inmemory_selections = selections
 3072                    .iter()
 3073                    .map(|s| {
 3074                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3075                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3076                    })
 3077                    .collect();
 3078                self.update_restoration_data(cx, |data| {
 3079                    data.selections = inmemory_selections;
 3080                });
 3081
 3082                if WorkspaceSettings::get(None, cx).restore_on_startup
 3083                    != RestoreOnStartupBehavior::None
 3084                {
 3085                    if let Some(workspace_id) =
 3086                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3087                    {
 3088                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3089                        let selections = selections.clone();
 3090                        let background_executor = cx.background_executor().clone();
 3091                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3092                        self.serialize_selections = cx.background_spawn(async move {
 3093                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3094                            let db_selections = selections
 3095                                .iter()
 3096                                .map(|selection| {
 3097                                    (
 3098                                        selection.start.to_offset(&snapshot),
 3099                                        selection.end.to_offset(&snapshot),
 3100                                    )
 3101                                })
 3102                                .collect();
 3103
 3104                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3105                                .await
 3106                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3107                                .log_err();
 3108                        });
 3109                    }
 3110                }
 3111            }
 3112        }
 3113
 3114        cx.notify();
 3115    }
 3116
 3117    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3118        use text::ToOffset as _;
 3119        use text::ToPoint as _;
 3120
 3121        if self.mode.is_minimap()
 3122            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3123        {
 3124            return;
 3125        }
 3126
 3127        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3128            return;
 3129        };
 3130
 3131        let snapshot = singleton.read(cx).snapshot();
 3132        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3133            let display_snapshot = display_map.snapshot(cx);
 3134
 3135            display_snapshot
 3136                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3137                .map(|fold| {
 3138                    fold.range.start.text_anchor.to_point(&snapshot)
 3139                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3140                })
 3141                .collect()
 3142        });
 3143        self.update_restoration_data(cx, |data| {
 3144            data.folds = inmemory_folds;
 3145        });
 3146
 3147        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3148            return;
 3149        };
 3150        let background_executor = cx.background_executor().clone();
 3151        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3152        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3153            display_map
 3154                .snapshot(cx)
 3155                .folds_in_range(0..snapshot.len())
 3156                .map(|fold| {
 3157                    (
 3158                        fold.range.start.text_anchor.to_offset(&snapshot),
 3159                        fold.range.end.text_anchor.to_offset(&snapshot),
 3160                    )
 3161                })
 3162                .collect()
 3163        });
 3164        self.serialize_folds = cx.background_spawn(async move {
 3165            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3166            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3167                .await
 3168                .with_context(|| {
 3169                    format!(
 3170                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3171                    )
 3172                })
 3173                .log_err();
 3174        });
 3175    }
 3176
 3177    pub fn sync_selections(
 3178        &mut self,
 3179        other: Entity<Editor>,
 3180        cx: &mut Context<Self>,
 3181    ) -> gpui::Subscription {
 3182        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3183        self.selections.change_with(cx, |selections| {
 3184            selections.select_anchors(other_selections);
 3185        });
 3186
 3187        let other_subscription =
 3188            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3189                EditorEvent::SelectionsChanged { local: true } => {
 3190                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3191                    if other_selections.is_empty() {
 3192                        return;
 3193                    }
 3194                    this.selections.change_with(cx, |selections| {
 3195                        selections.select_anchors(other_selections);
 3196                    });
 3197                }
 3198                _ => {}
 3199            });
 3200
 3201        let this_subscription =
 3202            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3203                EditorEvent::SelectionsChanged { local: true } => {
 3204                    let these_selections = this.selections.disjoint.to_vec();
 3205                    if these_selections.is_empty() {
 3206                        return;
 3207                    }
 3208                    other.update(cx, |other_editor, cx| {
 3209                        other_editor.selections.change_with(cx, |selections| {
 3210                            selections.select_anchors(these_selections);
 3211                        })
 3212                    });
 3213                }
 3214                _ => {}
 3215            });
 3216
 3217        Subscription::join(other_subscription, this_subscription)
 3218    }
 3219
 3220    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3221    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3222    /// effects of selection change occur at the end of the transaction.
 3223    pub fn change_selections<R>(
 3224        &mut self,
 3225        effects: SelectionEffects,
 3226        window: &mut Window,
 3227        cx: &mut Context<Self>,
 3228        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3229    ) -> R {
 3230        if let Some(state) = &mut self.deferred_selection_effects_state {
 3231            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3232            state.effects.completions = effects.completions;
 3233            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3234            let (changed, result) = self.selections.change_with(cx, change);
 3235            state.changed |= changed;
 3236            return result;
 3237        }
 3238        let mut state = DeferredSelectionEffectsState {
 3239            changed: false,
 3240            effects,
 3241            old_cursor_position: self.selections.newest_anchor().head(),
 3242            history_entry: SelectionHistoryEntry {
 3243                selections: self.selections.disjoint_anchors(),
 3244                select_next_state: self.select_next_state.clone(),
 3245                select_prev_state: self.select_prev_state.clone(),
 3246                add_selections_state: self.add_selections_state.clone(),
 3247            },
 3248        };
 3249        let (changed, result) = self.selections.change_with(cx, change);
 3250        state.changed = state.changed || changed;
 3251        if self.defer_selection_effects {
 3252            self.deferred_selection_effects_state = Some(state);
 3253        } else {
 3254            self.apply_selection_effects(state, window, cx);
 3255        }
 3256        result
 3257    }
 3258
 3259    /// Defers the effects of selection change, so that the effects of multiple calls to
 3260    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3261    /// to selection history and the state of popovers based on selection position aren't
 3262    /// erroneously updated.
 3263    pub fn with_selection_effects_deferred<R>(
 3264        &mut self,
 3265        window: &mut Window,
 3266        cx: &mut Context<Self>,
 3267        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3268    ) -> R {
 3269        let already_deferred = self.defer_selection_effects;
 3270        self.defer_selection_effects = true;
 3271        let result = update(self, window, cx);
 3272        if !already_deferred {
 3273            self.defer_selection_effects = false;
 3274            if let Some(state) = self.deferred_selection_effects_state.take() {
 3275                self.apply_selection_effects(state, window, cx);
 3276            }
 3277        }
 3278        result
 3279    }
 3280
 3281    fn apply_selection_effects(
 3282        &mut self,
 3283        state: DeferredSelectionEffectsState,
 3284        window: &mut Window,
 3285        cx: &mut Context<Self>,
 3286    ) {
 3287        if state.changed {
 3288            self.selection_history.push(state.history_entry);
 3289
 3290            if let Some(autoscroll) = state.effects.scroll {
 3291                self.request_autoscroll(autoscroll, cx);
 3292            }
 3293
 3294            let old_cursor_position = &state.old_cursor_position;
 3295
 3296            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3297
 3298            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3299                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3300            }
 3301        }
 3302    }
 3303
 3304    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3305    where
 3306        I: IntoIterator<Item = (Range<S>, T)>,
 3307        S: ToOffset,
 3308        T: Into<Arc<str>>,
 3309    {
 3310        if self.read_only(cx) {
 3311            return;
 3312        }
 3313
 3314        self.buffer
 3315            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3316    }
 3317
 3318    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3319    where
 3320        I: IntoIterator<Item = (Range<S>, T)>,
 3321        S: ToOffset,
 3322        T: Into<Arc<str>>,
 3323    {
 3324        if self.read_only(cx) {
 3325            return;
 3326        }
 3327
 3328        self.buffer.update(cx, |buffer, cx| {
 3329            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3330        });
 3331    }
 3332
 3333    pub fn edit_with_block_indent<I, S, T>(
 3334        &mut self,
 3335        edits: I,
 3336        original_indent_columns: Vec<Option<u32>>,
 3337        cx: &mut Context<Self>,
 3338    ) where
 3339        I: IntoIterator<Item = (Range<S>, T)>,
 3340        S: ToOffset,
 3341        T: Into<Arc<str>>,
 3342    {
 3343        if self.read_only(cx) {
 3344            return;
 3345        }
 3346
 3347        self.buffer.update(cx, |buffer, cx| {
 3348            buffer.edit(
 3349                edits,
 3350                Some(AutoindentMode::Block {
 3351                    original_indent_columns,
 3352                }),
 3353                cx,
 3354            )
 3355        });
 3356    }
 3357
 3358    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3359        self.hide_context_menu(window, cx);
 3360
 3361        match phase {
 3362            SelectPhase::Begin {
 3363                position,
 3364                add,
 3365                click_count,
 3366            } => self.begin_selection(position, add, click_count, window, cx),
 3367            SelectPhase::BeginColumnar {
 3368                position,
 3369                goal_column,
 3370                reset,
 3371                mode,
 3372            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3373            SelectPhase::Extend {
 3374                position,
 3375                click_count,
 3376            } => self.extend_selection(position, click_count, window, cx),
 3377            SelectPhase::Update {
 3378                position,
 3379                goal_column,
 3380                scroll_delta,
 3381            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3382            SelectPhase::End => self.end_selection(window, cx),
 3383        }
 3384    }
 3385
 3386    fn extend_selection(
 3387        &mut self,
 3388        position: DisplayPoint,
 3389        click_count: usize,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3394        let tail = self.selections.newest::<usize>(cx).tail();
 3395        self.begin_selection(position, false, click_count, window, cx);
 3396
 3397        let position = position.to_offset(&display_map, Bias::Left);
 3398        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3399
 3400        let mut pending_selection = self
 3401            .selections
 3402            .pending_anchor()
 3403            .expect("extend_selection not called with pending selection");
 3404        if position >= tail {
 3405            pending_selection.start = tail_anchor;
 3406        } else {
 3407            pending_selection.end = tail_anchor;
 3408            pending_selection.reversed = true;
 3409        }
 3410
 3411        let mut pending_mode = self.selections.pending_mode().unwrap();
 3412        match &mut pending_mode {
 3413            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3414            _ => {}
 3415        }
 3416
 3417        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3418            SelectionEffects::scroll(Autoscroll::fit())
 3419        } else {
 3420            SelectionEffects::no_scroll()
 3421        };
 3422
 3423        self.change_selections(effects, window, cx, |s| {
 3424            s.set_pending(pending_selection, pending_mode)
 3425        });
 3426    }
 3427
 3428    fn begin_selection(
 3429        &mut self,
 3430        position: DisplayPoint,
 3431        add: bool,
 3432        click_count: usize,
 3433        window: &mut Window,
 3434        cx: &mut Context<Self>,
 3435    ) {
 3436        if !self.focus_handle.is_focused(window) {
 3437            self.last_focused_descendant = None;
 3438            window.focus(&self.focus_handle);
 3439        }
 3440
 3441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3442        let buffer = &display_map.buffer_snapshot;
 3443        let position = display_map.clip_point(position, Bias::Left);
 3444
 3445        let start;
 3446        let end;
 3447        let mode;
 3448        let mut auto_scroll;
 3449        match click_count {
 3450            1 => {
 3451                start = buffer.anchor_before(position.to_point(&display_map));
 3452                end = start;
 3453                mode = SelectMode::Character;
 3454                auto_scroll = true;
 3455            }
 3456            2 => {
 3457                let position = display_map
 3458                    .clip_point(position, Bias::Left)
 3459                    .to_offset(&display_map, Bias::Left);
 3460                let (range, _) = buffer.surrounding_word(position, false);
 3461                start = buffer.anchor_before(range.start);
 3462                end = buffer.anchor_before(range.end);
 3463                mode = SelectMode::Word(start..end);
 3464                auto_scroll = true;
 3465            }
 3466            3 => {
 3467                let position = display_map
 3468                    .clip_point(position, Bias::Left)
 3469                    .to_point(&display_map);
 3470                let line_start = display_map.prev_line_boundary(position).0;
 3471                let next_line_start = buffer.clip_point(
 3472                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3473                    Bias::Left,
 3474                );
 3475                start = buffer.anchor_before(line_start);
 3476                end = buffer.anchor_before(next_line_start);
 3477                mode = SelectMode::Line(start..end);
 3478                auto_scroll = true;
 3479            }
 3480            _ => {
 3481                start = buffer.anchor_before(0);
 3482                end = buffer.anchor_before(buffer.len());
 3483                mode = SelectMode::All;
 3484                auto_scroll = false;
 3485            }
 3486        }
 3487        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3488
 3489        let point_to_delete: Option<usize> = {
 3490            let selected_points: Vec<Selection<Point>> =
 3491                self.selections.disjoint_in_range(start..end, cx);
 3492
 3493            if !add || click_count > 1 {
 3494                None
 3495            } else if !selected_points.is_empty() {
 3496                Some(selected_points[0].id)
 3497            } else {
 3498                let clicked_point_already_selected =
 3499                    self.selections.disjoint.iter().find(|selection| {
 3500                        selection.start.to_point(buffer) == start.to_point(buffer)
 3501                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3502                    });
 3503
 3504                clicked_point_already_selected.map(|selection| selection.id)
 3505            }
 3506        };
 3507
 3508        let selections_count = self.selections.count();
 3509        let effects = if auto_scroll {
 3510            SelectionEffects::default()
 3511        } else {
 3512            SelectionEffects::no_scroll()
 3513        };
 3514
 3515        self.change_selections(effects, window, cx, |s| {
 3516            if let Some(point_to_delete) = point_to_delete {
 3517                s.delete(point_to_delete);
 3518
 3519                if selections_count == 1 {
 3520                    s.set_pending_anchor_range(start..end, mode);
 3521                }
 3522            } else {
 3523                if !add {
 3524                    s.clear_disjoint();
 3525                }
 3526
 3527                s.set_pending_anchor_range(start..end, mode);
 3528            }
 3529        });
 3530    }
 3531
 3532    fn begin_columnar_selection(
 3533        &mut self,
 3534        position: DisplayPoint,
 3535        goal_column: u32,
 3536        reset: bool,
 3537        mode: ColumnarMode,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) {
 3541        if !self.focus_handle.is_focused(window) {
 3542            self.last_focused_descendant = None;
 3543            window.focus(&self.focus_handle);
 3544        }
 3545
 3546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3547
 3548        if reset {
 3549            let pointer_position = display_map
 3550                .buffer_snapshot
 3551                .anchor_before(position.to_point(&display_map));
 3552
 3553            self.change_selections(
 3554                SelectionEffects::scroll(Autoscroll::newest()),
 3555                window,
 3556                cx,
 3557                |s| {
 3558                    s.clear_disjoint();
 3559                    s.set_pending_anchor_range(
 3560                        pointer_position..pointer_position,
 3561                        SelectMode::Character,
 3562                    );
 3563                },
 3564            );
 3565        };
 3566
 3567        let tail = self.selections.newest::<Point>(cx).tail();
 3568        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3569        self.columnar_selection_state = match mode {
 3570            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3571                selection_tail: selection_anchor,
 3572                display_point: if reset {
 3573                    if position.column() != goal_column {
 3574                        Some(DisplayPoint::new(position.row(), goal_column))
 3575                    } else {
 3576                        None
 3577                    }
 3578                } else {
 3579                    None
 3580                },
 3581            }),
 3582            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3583                selection_tail: selection_anchor,
 3584            }),
 3585        };
 3586
 3587        if !reset {
 3588            self.select_columns(position, goal_column, &display_map, window, cx);
 3589        }
 3590    }
 3591
 3592    fn update_selection(
 3593        &mut self,
 3594        position: DisplayPoint,
 3595        goal_column: u32,
 3596        scroll_delta: gpui::Point<f32>,
 3597        window: &mut Window,
 3598        cx: &mut Context<Self>,
 3599    ) {
 3600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3601
 3602        if self.columnar_selection_state.is_some() {
 3603            self.select_columns(position, goal_column, &display_map, window, cx);
 3604        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3605            let buffer = &display_map.buffer_snapshot;
 3606            let head;
 3607            let tail;
 3608            let mode = self.selections.pending_mode().unwrap();
 3609            match &mode {
 3610                SelectMode::Character => {
 3611                    head = position.to_point(&display_map);
 3612                    tail = pending.tail().to_point(buffer);
 3613                }
 3614                SelectMode::Word(original_range) => {
 3615                    let offset = display_map
 3616                        .clip_point(position, Bias::Left)
 3617                        .to_offset(&display_map, Bias::Left);
 3618                    let original_range = original_range.to_offset(buffer);
 3619
 3620                    let head_offset = if buffer.is_inside_word(offset, false)
 3621                        || original_range.contains(&offset)
 3622                    {
 3623                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3624                        if word_range.start < original_range.start {
 3625                            word_range.start
 3626                        } else {
 3627                            word_range.end
 3628                        }
 3629                    } else {
 3630                        offset
 3631                    };
 3632
 3633                    head = head_offset.to_point(buffer);
 3634                    if head_offset <= original_range.start {
 3635                        tail = original_range.end.to_point(buffer);
 3636                    } else {
 3637                        tail = original_range.start.to_point(buffer);
 3638                    }
 3639                }
 3640                SelectMode::Line(original_range) => {
 3641                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3642
 3643                    let position = display_map
 3644                        .clip_point(position, Bias::Left)
 3645                        .to_point(&display_map);
 3646                    let line_start = display_map.prev_line_boundary(position).0;
 3647                    let next_line_start = buffer.clip_point(
 3648                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3649                        Bias::Left,
 3650                    );
 3651
 3652                    if line_start < original_range.start {
 3653                        head = line_start
 3654                    } else {
 3655                        head = next_line_start
 3656                    }
 3657
 3658                    if head <= original_range.start {
 3659                        tail = original_range.end;
 3660                    } else {
 3661                        tail = original_range.start;
 3662                    }
 3663                }
 3664                SelectMode::All => {
 3665                    return;
 3666                }
 3667            };
 3668
 3669            if head < tail {
 3670                pending.start = buffer.anchor_before(head);
 3671                pending.end = buffer.anchor_before(tail);
 3672                pending.reversed = true;
 3673            } else {
 3674                pending.start = buffer.anchor_before(tail);
 3675                pending.end = buffer.anchor_before(head);
 3676                pending.reversed = false;
 3677            }
 3678
 3679            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3680                s.set_pending(pending, mode);
 3681            });
 3682        } else {
 3683            log::error!("update_selection dispatched with no pending selection");
 3684            return;
 3685        }
 3686
 3687        self.apply_scroll_delta(scroll_delta, window, cx);
 3688        cx.notify();
 3689    }
 3690
 3691    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3692        self.columnar_selection_state.take();
 3693        if self.selections.pending_anchor().is_some() {
 3694            let selections = self.selections.all::<usize>(cx);
 3695            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3696                s.select(selections);
 3697                s.clear_pending();
 3698            });
 3699        }
 3700    }
 3701
 3702    fn select_columns(
 3703        &mut self,
 3704        head: DisplayPoint,
 3705        goal_column: u32,
 3706        display_map: &DisplaySnapshot,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3711            return;
 3712        };
 3713
 3714        let tail = match columnar_state {
 3715            ColumnarSelectionState::FromMouse {
 3716                selection_tail,
 3717                display_point,
 3718            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3719            ColumnarSelectionState::FromSelection { selection_tail } => {
 3720                selection_tail.to_display_point(&display_map)
 3721            }
 3722        };
 3723
 3724        let start_row = cmp::min(tail.row(), head.row());
 3725        let end_row = cmp::max(tail.row(), head.row());
 3726        let start_column = cmp::min(tail.column(), goal_column);
 3727        let end_column = cmp::max(tail.column(), goal_column);
 3728        let reversed = start_column < tail.column();
 3729
 3730        let selection_ranges = (start_row.0..=end_row.0)
 3731            .map(DisplayRow)
 3732            .filter_map(|row| {
 3733                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3734                    || start_column <= display_map.line_len(row))
 3735                    && !display_map.is_block_line(row)
 3736                {
 3737                    let start = display_map
 3738                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3739                        .to_point(display_map);
 3740                    let end = display_map
 3741                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3742                        .to_point(display_map);
 3743                    if reversed {
 3744                        Some(end..start)
 3745                    } else {
 3746                        Some(start..end)
 3747                    }
 3748                } else {
 3749                    None
 3750                }
 3751            })
 3752            .collect::<Vec<_>>();
 3753
 3754        let ranges = match columnar_state {
 3755            ColumnarSelectionState::FromMouse { .. } => {
 3756                let mut non_empty_ranges = selection_ranges
 3757                    .iter()
 3758                    .filter(|selection_range| selection_range.start != selection_range.end)
 3759                    .peekable();
 3760                if non_empty_ranges.peek().is_some() {
 3761                    non_empty_ranges.cloned().collect()
 3762                } else {
 3763                    selection_ranges
 3764                }
 3765            }
 3766            _ => selection_ranges,
 3767        };
 3768
 3769        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3770            s.select_ranges(ranges);
 3771        });
 3772        cx.notify();
 3773    }
 3774
 3775    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3776        self.selections
 3777            .all_adjusted(cx)
 3778            .iter()
 3779            .any(|selection| !selection.is_empty())
 3780    }
 3781
 3782    pub fn has_pending_nonempty_selection(&self) -> bool {
 3783        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3784            Some(Selection { start, end, .. }) => start != end,
 3785            None => false,
 3786        };
 3787
 3788        pending_nonempty_selection
 3789            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3790    }
 3791
 3792    pub fn has_pending_selection(&self) -> bool {
 3793        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3794    }
 3795
 3796    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3797        self.selection_mark_mode = false;
 3798        self.selection_drag_state = SelectionDragState::None;
 3799
 3800        if self.clear_expanded_diff_hunks(cx) {
 3801            cx.notify();
 3802            return;
 3803        }
 3804        if self.dismiss_menus_and_popups(true, window, cx) {
 3805            return;
 3806        }
 3807
 3808        if self.mode.is_full()
 3809            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3810        {
 3811            return;
 3812        }
 3813
 3814        cx.propagate();
 3815    }
 3816
 3817    pub fn dismiss_menus_and_popups(
 3818        &mut self,
 3819        is_user_requested: bool,
 3820        window: &mut Window,
 3821        cx: &mut Context<Self>,
 3822    ) -> bool {
 3823        if self.take_rename(false, window, cx).is_some() {
 3824            return true;
 3825        }
 3826
 3827        if hide_hover(self, cx) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3832            return true;
 3833        }
 3834
 3835        if self.hide_context_menu(window, cx).is_some() {
 3836            return true;
 3837        }
 3838
 3839        if self.mouse_context_menu.take().is_some() {
 3840            return true;
 3841        }
 3842
 3843        if is_user_requested && self.discard_inline_completion(true, cx) {
 3844            return true;
 3845        }
 3846
 3847        if self.snippet_stack.pop().is_some() {
 3848            return true;
 3849        }
 3850
 3851        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3852            self.dismiss_diagnostics(cx);
 3853            return true;
 3854        }
 3855
 3856        false
 3857    }
 3858
 3859    fn linked_editing_ranges_for(
 3860        &self,
 3861        selection: Range<text::Anchor>,
 3862        cx: &App,
 3863    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3864        if self.linked_edit_ranges.is_empty() {
 3865            return None;
 3866        }
 3867        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3868            selection.end.buffer_id.and_then(|end_buffer_id| {
 3869                if selection.start.buffer_id != Some(end_buffer_id) {
 3870                    return None;
 3871                }
 3872                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3873                let snapshot = buffer.read(cx).snapshot();
 3874                self.linked_edit_ranges
 3875                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3876                    .map(|ranges| (ranges, snapshot, buffer))
 3877            })?;
 3878        use text::ToOffset as TO;
 3879        // find offset from the start of current range to current cursor position
 3880        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3881
 3882        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3883        let start_difference = start_offset - start_byte_offset;
 3884        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3885        let end_difference = end_offset - start_byte_offset;
 3886        // Current range has associated linked ranges.
 3887        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3888        for range in linked_ranges.iter() {
 3889            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3890            let end_offset = start_offset + end_difference;
 3891            let start_offset = start_offset + start_difference;
 3892            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3893                continue;
 3894            }
 3895            if self.selections.disjoint_anchor_ranges().any(|s| {
 3896                if s.start.buffer_id != selection.start.buffer_id
 3897                    || s.end.buffer_id != selection.end.buffer_id
 3898                {
 3899                    return false;
 3900                }
 3901                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3902                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3903            }) {
 3904                continue;
 3905            }
 3906            let start = buffer_snapshot.anchor_after(start_offset);
 3907            let end = buffer_snapshot.anchor_after(end_offset);
 3908            linked_edits
 3909                .entry(buffer.clone())
 3910                .or_default()
 3911                .push(start..end);
 3912        }
 3913        Some(linked_edits)
 3914    }
 3915
 3916    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3917        let text: Arc<str> = text.into();
 3918
 3919        if self.read_only(cx) {
 3920            return;
 3921        }
 3922
 3923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3924
 3925        let selections = self.selections.all_adjusted(cx);
 3926        let mut bracket_inserted = false;
 3927        let mut edits = Vec::new();
 3928        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3929        let mut new_selections = Vec::with_capacity(selections.len());
 3930        let mut new_autoclose_regions = Vec::new();
 3931        let snapshot = self.buffer.read(cx).read(cx);
 3932        let mut clear_linked_edit_ranges = false;
 3933
 3934        for (selection, autoclose_region) in
 3935            self.selections_with_autoclose_regions(selections, &snapshot)
 3936        {
 3937            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3938                // Determine if the inserted text matches the opening or closing
 3939                // bracket of any of this language's bracket pairs.
 3940                let mut bracket_pair = None;
 3941                let mut is_bracket_pair_start = false;
 3942                let mut is_bracket_pair_end = false;
 3943                if !text.is_empty() {
 3944                    let mut bracket_pair_matching_end = None;
 3945                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3946                    //  and they are removing the character that triggered IME popup.
 3947                    for (pair, enabled) in scope.brackets() {
 3948                        if !pair.close && !pair.surround {
 3949                            continue;
 3950                        }
 3951
 3952                        if enabled && pair.start.ends_with(text.as_ref()) {
 3953                            let prefix_len = pair.start.len() - text.len();
 3954                            let preceding_text_matches_prefix = prefix_len == 0
 3955                                || (selection.start.column >= (prefix_len as u32)
 3956                                    && snapshot.contains_str_at(
 3957                                        Point::new(
 3958                                            selection.start.row,
 3959                                            selection.start.column - (prefix_len as u32),
 3960                                        ),
 3961                                        &pair.start[..prefix_len],
 3962                                    ));
 3963                            if preceding_text_matches_prefix {
 3964                                bracket_pair = Some(pair.clone());
 3965                                is_bracket_pair_start = true;
 3966                                break;
 3967                            }
 3968                        }
 3969                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3970                        {
 3971                            // take first bracket pair matching end, but don't break in case a later bracket
 3972                            // pair matches start
 3973                            bracket_pair_matching_end = Some(pair.clone());
 3974                        }
 3975                    }
 3976                    if let Some(end) = bracket_pair_matching_end
 3977                        && bracket_pair.is_none()
 3978                    {
 3979                        bracket_pair = Some(end);
 3980                        is_bracket_pair_end = true;
 3981                    }
 3982                }
 3983
 3984                if let Some(bracket_pair) = bracket_pair {
 3985                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3986                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3987                    let auto_surround =
 3988                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3989                    if selection.is_empty() {
 3990                        if is_bracket_pair_start {
 3991                            // If the inserted text is a suffix of an opening bracket and the
 3992                            // selection is preceded by the rest of the opening bracket, then
 3993                            // insert the closing bracket.
 3994                            let following_text_allows_autoclose = snapshot
 3995                                .chars_at(selection.start)
 3996                                .next()
 3997                                .map_or(true, |c| scope.should_autoclose_before(c));
 3998
 3999                            let preceding_text_allows_autoclose = selection.start.column == 0
 4000                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4001                                    true,
 4002                                    |c| {
 4003                                        bracket_pair.start != bracket_pair.end
 4004                                            || !snapshot
 4005                                                .char_classifier_at(selection.start)
 4006                                                .is_word(c)
 4007                                    },
 4008                                );
 4009
 4010                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4011                                && bracket_pair.start.len() == 1
 4012                            {
 4013                                let target = bracket_pair.start.chars().next().unwrap();
 4014                                let current_line_count = snapshot
 4015                                    .reversed_chars_at(selection.start)
 4016                                    .take_while(|&c| c != '\n')
 4017                                    .filter(|&c| c == target)
 4018                                    .count();
 4019                                current_line_count % 2 == 1
 4020                            } else {
 4021                                false
 4022                            };
 4023
 4024                            if autoclose
 4025                                && bracket_pair.close
 4026                                && following_text_allows_autoclose
 4027                                && preceding_text_allows_autoclose
 4028                                && !is_closing_quote
 4029                            {
 4030                                let anchor = snapshot.anchor_before(selection.end);
 4031                                new_selections.push((selection.map(|_| anchor), text.len()));
 4032                                new_autoclose_regions.push((
 4033                                    anchor,
 4034                                    text.len(),
 4035                                    selection.id,
 4036                                    bracket_pair.clone(),
 4037                                ));
 4038                                edits.push((
 4039                                    selection.range(),
 4040                                    format!("{}{}", text, bracket_pair.end).into(),
 4041                                ));
 4042                                bracket_inserted = true;
 4043                                continue;
 4044                            }
 4045                        }
 4046
 4047                        if let Some(region) = autoclose_region {
 4048                            // If the selection is followed by an auto-inserted closing bracket,
 4049                            // then don't insert that closing bracket again; just move the selection
 4050                            // past the closing bracket.
 4051                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4052                                && text.as_ref() == region.pair.end.as_str()
 4053                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4054                            if should_skip {
 4055                                let anchor = snapshot.anchor_after(selection.end);
 4056                                new_selections
 4057                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4058                                continue;
 4059                            }
 4060                        }
 4061
 4062                        let always_treat_brackets_as_autoclosed = snapshot
 4063                            .language_settings_at(selection.start, cx)
 4064                            .always_treat_brackets_as_autoclosed;
 4065                        if always_treat_brackets_as_autoclosed
 4066                            && is_bracket_pair_end
 4067                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4068                        {
 4069                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4070                            // and the inserted text is a closing bracket and the selection is followed
 4071                            // by the closing bracket then move the selection past the closing bracket.
 4072                            let anchor = snapshot.anchor_after(selection.end);
 4073                            new_selections.push((selection.map(|_| anchor), text.len()));
 4074                            continue;
 4075                        }
 4076                    }
 4077                    // If an opening bracket is 1 character long and is typed while
 4078                    // text is selected, then surround that text with the bracket pair.
 4079                    else if auto_surround
 4080                        && bracket_pair.surround
 4081                        && is_bracket_pair_start
 4082                        && bracket_pair.start.chars().count() == 1
 4083                    {
 4084                        edits.push((selection.start..selection.start, text.clone()));
 4085                        edits.push((
 4086                            selection.end..selection.end,
 4087                            bracket_pair.end.as_str().into(),
 4088                        ));
 4089                        bracket_inserted = true;
 4090                        new_selections.push((
 4091                            Selection {
 4092                                id: selection.id,
 4093                                start: snapshot.anchor_after(selection.start),
 4094                                end: snapshot.anchor_before(selection.end),
 4095                                reversed: selection.reversed,
 4096                                goal: selection.goal,
 4097                            },
 4098                            0,
 4099                        ));
 4100                        continue;
 4101                    }
 4102                }
 4103            }
 4104
 4105            if self.auto_replace_emoji_shortcode
 4106                && selection.is_empty()
 4107                && text.as_ref().ends_with(':')
 4108            {
 4109                if let Some(possible_emoji_short_code) =
 4110                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4111                {
 4112                    if !possible_emoji_short_code.is_empty() {
 4113                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4114                            let emoji_shortcode_start = Point::new(
 4115                                selection.start.row,
 4116                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4117                            );
 4118
 4119                            // Remove shortcode from buffer
 4120                            edits.push((
 4121                                emoji_shortcode_start..selection.start,
 4122                                "".to_string().into(),
 4123                            ));
 4124                            new_selections.push((
 4125                                Selection {
 4126                                    id: selection.id,
 4127                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4128                                    end: snapshot.anchor_before(selection.start),
 4129                                    reversed: selection.reversed,
 4130                                    goal: selection.goal,
 4131                                },
 4132                                0,
 4133                            ));
 4134
 4135                            // Insert emoji
 4136                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4137                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4138                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4139
 4140                            continue;
 4141                        }
 4142                    }
 4143                }
 4144            }
 4145
 4146            // If not handling any auto-close operation, then just replace the selected
 4147            // text with the given input and move the selection to the end of the
 4148            // newly inserted text.
 4149            let anchor = snapshot.anchor_after(selection.end);
 4150            if !self.linked_edit_ranges.is_empty() {
 4151                let start_anchor = snapshot.anchor_before(selection.start);
 4152
 4153                let is_word_char = text.chars().next().map_or(true, |char| {
 4154                    let classifier = snapshot
 4155                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4156                        .ignore_punctuation(true);
 4157                    classifier.is_word(char)
 4158                });
 4159
 4160                if is_word_char {
 4161                    if let Some(ranges) = self
 4162                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4163                    {
 4164                        for (buffer, edits) in ranges {
 4165                            linked_edits
 4166                                .entry(buffer.clone())
 4167                                .or_default()
 4168                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4169                        }
 4170                    }
 4171                } else {
 4172                    clear_linked_edit_ranges = true;
 4173                }
 4174            }
 4175
 4176            new_selections.push((selection.map(|_| anchor), 0));
 4177            edits.push((selection.start..selection.end, text.clone()));
 4178        }
 4179
 4180        drop(snapshot);
 4181
 4182        self.transact(window, cx, |this, window, cx| {
 4183            if clear_linked_edit_ranges {
 4184                this.linked_edit_ranges.clear();
 4185            }
 4186            let initial_buffer_versions =
 4187                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4188
 4189            this.buffer.update(cx, |buffer, cx| {
 4190                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4191            });
 4192            for (buffer, edits) in linked_edits {
 4193                buffer.update(cx, |buffer, cx| {
 4194                    let snapshot = buffer.snapshot();
 4195                    let edits = edits
 4196                        .into_iter()
 4197                        .map(|(range, text)| {
 4198                            use text::ToPoint as TP;
 4199                            let end_point = TP::to_point(&range.end, &snapshot);
 4200                            let start_point = TP::to_point(&range.start, &snapshot);
 4201                            (start_point..end_point, text)
 4202                        })
 4203                        .sorted_by_key(|(range, _)| range.start);
 4204                    buffer.edit(edits, None, cx);
 4205                })
 4206            }
 4207            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4208            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4209            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4210            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4211                .zip(new_selection_deltas)
 4212                .map(|(selection, delta)| Selection {
 4213                    id: selection.id,
 4214                    start: selection.start + delta,
 4215                    end: selection.end + delta,
 4216                    reversed: selection.reversed,
 4217                    goal: SelectionGoal::None,
 4218                })
 4219                .collect::<Vec<_>>();
 4220
 4221            let mut i = 0;
 4222            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4223                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4224                let start = map.buffer_snapshot.anchor_before(position);
 4225                let end = map.buffer_snapshot.anchor_after(position);
 4226                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4227                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4228                        Ordering::Less => i += 1,
 4229                        Ordering::Greater => break,
 4230                        Ordering::Equal => {
 4231                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4232                                Ordering::Less => i += 1,
 4233                                Ordering::Equal => break,
 4234                                Ordering::Greater => break,
 4235                            }
 4236                        }
 4237                    }
 4238                }
 4239                this.autoclose_regions.insert(
 4240                    i,
 4241                    AutocloseRegion {
 4242                        selection_id,
 4243                        range: start..end,
 4244                        pair,
 4245                    },
 4246                );
 4247            }
 4248
 4249            let had_active_inline_completion = this.has_active_inline_completion();
 4250            this.change_selections(
 4251                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4252                window,
 4253                cx,
 4254                |s| s.select(new_selections),
 4255            );
 4256
 4257            if !bracket_inserted {
 4258                if let Some(on_type_format_task) =
 4259                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4260                {
 4261                    on_type_format_task.detach_and_log_err(cx);
 4262                }
 4263            }
 4264
 4265            let editor_settings = EditorSettings::get_global(cx);
 4266            if bracket_inserted
 4267                && (editor_settings.auto_signature_help
 4268                    || editor_settings.show_signature_help_after_edits)
 4269            {
 4270                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4271            }
 4272
 4273            let trigger_in_words =
 4274                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4275            if this.hard_wrap.is_some() {
 4276                let latest: Range<Point> = this.selections.newest(cx).range();
 4277                if latest.is_empty()
 4278                    && this
 4279                        .buffer()
 4280                        .read(cx)
 4281                        .snapshot(cx)
 4282                        .line_len(MultiBufferRow(latest.start.row))
 4283                        == latest.start.column
 4284                {
 4285                    this.rewrap_impl(
 4286                        RewrapOptions {
 4287                            override_language_settings: true,
 4288                            preserve_existing_whitespace: true,
 4289                        },
 4290                        cx,
 4291                    )
 4292                }
 4293            }
 4294            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4295            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4296            this.refresh_inline_completion(true, false, window, cx);
 4297            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4298        });
 4299    }
 4300
 4301    fn find_possible_emoji_shortcode_at_position(
 4302        snapshot: &MultiBufferSnapshot,
 4303        position: Point,
 4304    ) -> Option<String> {
 4305        let mut chars = Vec::new();
 4306        let mut found_colon = false;
 4307        for char in snapshot.reversed_chars_at(position).take(100) {
 4308            // Found a possible emoji shortcode in the middle of the buffer
 4309            if found_colon {
 4310                if char.is_whitespace() {
 4311                    chars.reverse();
 4312                    return Some(chars.iter().collect());
 4313                }
 4314                // If the previous character is not a whitespace, we are in the middle of a word
 4315                // and we only want to complete the shortcode if the word is made up of other emojis
 4316                let mut containing_word = String::new();
 4317                for ch in snapshot
 4318                    .reversed_chars_at(position)
 4319                    .skip(chars.len() + 1)
 4320                    .take(100)
 4321                {
 4322                    if ch.is_whitespace() {
 4323                        break;
 4324                    }
 4325                    containing_word.push(ch);
 4326                }
 4327                let containing_word = containing_word.chars().rev().collect::<String>();
 4328                if util::word_consists_of_emojis(containing_word.as_str()) {
 4329                    chars.reverse();
 4330                    return Some(chars.iter().collect());
 4331                }
 4332            }
 4333
 4334            if char.is_whitespace() || !char.is_ascii() {
 4335                return None;
 4336            }
 4337            if char == ':' {
 4338                found_colon = true;
 4339            } else {
 4340                chars.push(char);
 4341            }
 4342        }
 4343        // Found a possible emoji shortcode at the beginning of the buffer
 4344        chars.reverse();
 4345        Some(chars.iter().collect())
 4346    }
 4347
 4348    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4350        self.transact(window, cx, |this, window, cx| {
 4351            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4352                let selections = this.selections.all::<usize>(cx);
 4353                let multi_buffer = this.buffer.read(cx);
 4354                let buffer = multi_buffer.snapshot(cx);
 4355                selections
 4356                    .iter()
 4357                    .map(|selection| {
 4358                        let start_point = selection.start.to_point(&buffer);
 4359                        let mut existing_indent =
 4360                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4361                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4362                        let start = selection.start;
 4363                        let end = selection.end;
 4364                        let selection_is_empty = start == end;
 4365                        let language_scope = buffer.language_scope_at(start);
 4366                        let (
 4367                            comment_delimiter,
 4368                            doc_delimiter,
 4369                            insert_extra_newline,
 4370                            indent_on_newline,
 4371                            indent_on_extra_newline,
 4372                        ) = if let Some(language) = &language_scope {
 4373                            let mut insert_extra_newline =
 4374                                insert_extra_newline_brackets(&buffer, start..end, language)
 4375                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4376
 4377                            // Comment extension on newline is allowed only for cursor selections
 4378                            let comment_delimiter = maybe!({
 4379                                if !selection_is_empty {
 4380                                    return None;
 4381                                }
 4382
 4383                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4384                                    return None;
 4385                                }
 4386
 4387                                let delimiters = language.line_comment_prefixes();
 4388                                let max_len_of_delimiter =
 4389                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4390                                let (snapshot, range) =
 4391                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4392
 4393                                let num_of_whitespaces = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .take_while(|c| c.is_whitespace())
 4396                                    .count();
 4397                                let comment_candidate = snapshot
 4398                                    .chars_for_range(range.clone())
 4399                                    .skip(num_of_whitespaces)
 4400                                    .take(max_len_of_delimiter)
 4401                                    .collect::<String>();
 4402                                let (delimiter, trimmed_len) = delimiters
 4403                                    .iter()
 4404                                    .filter_map(|delimiter| {
 4405                                        let prefix = delimiter.trim_end();
 4406                                        if comment_candidate.starts_with(prefix) {
 4407                                            Some((delimiter, prefix.len()))
 4408                                        } else {
 4409                                            None
 4410                                        }
 4411                                    })
 4412                                    .max_by_key(|(_, len)| *len)?;
 4413
 4414                                if let Some(BlockCommentConfig {
 4415                                    start: block_start, ..
 4416                                }) = language.block_comment()
 4417                                {
 4418                                    let block_start_trimmed = block_start.trim_end();
 4419                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4420                                        let line_content = snapshot
 4421                                            .chars_for_range(range)
 4422                                            .skip(num_of_whitespaces)
 4423                                            .take(block_start_trimmed.len())
 4424                                            .collect::<String>();
 4425
 4426                                        if line_content.starts_with(block_start_trimmed) {
 4427                                            return None;
 4428                                        }
 4429                                    }
 4430                                }
 4431
 4432                                let cursor_is_placed_after_comment_marker =
 4433                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4434                                if cursor_is_placed_after_comment_marker {
 4435                                    Some(delimiter.clone())
 4436                                } else {
 4437                                    None
 4438                                }
 4439                            });
 4440
 4441                            let mut indent_on_newline = IndentSize::spaces(0);
 4442                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4443
 4444                            let doc_delimiter = maybe!({
 4445                                if !selection_is_empty {
 4446                                    return None;
 4447                                }
 4448
 4449                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4450                                    return None;
 4451                                }
 4452
 4453                                let BlockCommentConfig {
 4454                                    start: start_tag,
 4455                                    end: end_tag,
 4456                                    prefix: delimiter,
 4457                                    tab_size: len,
 4458                                } = language.documentation_comment()?;
 4459                                let is_within_block_comment = buffer
 4460                                    .language_scope_at(start_point)
 4461                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4462                                if !is_within_block_comment {
 4463                                    return None;
 4464                                }
 4465
 4466                                let (snapshot, range) =
 4467                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4468
 4469                                let num_of_whitespaces = snapshot
 4470                                    .chars_for_range(range.clone())
 4471                                    .take_while(|c| c.is_whitespace())
 4472                                    .count();
 4473
 4474                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4475                                let column = start_point.column;
 4476                                let cursor_is_after_start_tag = {
 4477                                    let start_tag_len = start_tag.len();
 4478                                    let start_tag_line = snapshot
 4479                                        .chars_for_range(range.clone())
 4480                                        .skip(num_of_whitespaces)
 4481                                        .take(start_tag_len)
 4482                                        .collect::<String>();
 4483                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4484                                        num_of_whitespaces + start_tag_len <= column as usize
 4485                                    } else {
 4486                                        false
 4487                                    }
 4488                                };
 4489
 4490                                let cursor_is_after_delimiter = {
 4491                                    let delimiter_trim = delimiter.trim_end();
 4492                                    let delimiter_line = snapshot
 4493                                        .chars_for_range(range.clone())
 4494                                        .skip(num_of_whitespaces)
 4495                                        .take(delimiter_trim.len())
 4496                                        .collect::<String>();
 4497                                    if delimiter_line.starts_with(delimiter_trim) {
 4498                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4499                                    } else {
 4500                                        false
 4501                                    }
 4502                                };
 4503
 4504                                let cursor_is_before_end_tag_if_exists = {
 4505                                    let mut char_position = 0u32;
 4506                                    let mut end_tag_offset = None;
 4507
 4508                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4509                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4510                                            let chars_before_match =
 4511                                                chunk[..byte_pos].chars().count() as u32;
 4512                                            end_tag_offset =
 4513                                                Some(char_position + chars_before_match);
 4514                                            break 'outer;
 4515                                        }
 4516                                        char_position += chunk.chars().count() as u32;
 4517                                    }
 4518
 4519                                    if let Some(end_tag_offset) = end_tag_offset {
 4520                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4521                                        if cursor_is_after_start_tag {
 4522                                            if cursor_is_before_end_tag {
 4523                                                insert_extra_newline = true;
 4524                                            }
 4525                                            let cursor_is_at_start_of_end_tag =
 4526                                                column == end_tag_offset;
 4527                                            if cursor_is_at_start_of_end_tag {
 4528                                                indent_on_extra_newline.len = *len;
 4529                                            }
 4530                                        }
 4531                                        cursor_is_before_end_tag
 4532                                    } else {
 4533                                        true
 4534                                    }
 4535                                };
 4536
 4537                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4538                                    && cursor_is_before_end_tag_if_exists
 4539                                {
 4540                                    if cursor_is_after_start_tag {
 4541                                        indent_on_newline.len = *len;
 4542                                    }
 4543                                    Some(delimiter.clone())
 4544                                } else {
 4545                                    None
 4546                                }
 4547                            });
 4548
 4549                            (
 4550                                comment_delimiter,
 4551                                doc_delimiter,
 4552                                insert_extra_newline,
 4553                                indent_on_newline,
 4554                                indent_on_extra_newline,
 4555                            )
 4556                        } else {
 4557                            (
 4558                                None,
 4559                                None,
 4560                                false,
 4561                                IndentSize::default(),
 4562                                IndentSize::default(),
 4563                            )
 4564                        };
 4565
 4566                        let prevent_auto_indent = doc_delimiter.is_some();
 4567                        let delimiter = comment_delimiter.or(doc_delimiter);
 4568
 4569                        let capacity_for_delimiter =
 4570                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4571                        let mut new_text = String::with_capacity(
 4572                            1 + capacity_for_delimiter
 4573                                + existing_indent.len as usize
 4574                                + indent_on_newline.len as usize
 4575                                + indent_on_extra_newline.len as usize,
 4576                        );
 4577                        new_text.push('\n');
 4578                        new_text.extend(existing_indent.chars());
 4579                        new_text.extend(indent_on_newline.chars());
 4580
 4581                        if let Some(delimiter) = &delimiter {
 4582                            new_text.push_str(delimiter);
 4583                        }
 4584
 4585                        if insert_extra_newline {
 4586                            new_text.push('\n');
 4587                            new_text.extend(existing_indent.chars());
 4588                            new_text.extend(indent_on_extra_newline.chars());
 4589                        }
 4590
 4591                        let anchor = buffer.anchor_after(end);
 4592                        let new_selection = selection.map(|_| anchor);
 4593                        (
 4594                            ((start..end, new_text), prevent_auto_indent),
 4595                            (insert_extra_newline, new_selection),
 4596                        )
 4597                    })
 4598                    .unzip()
 4599            };
 4600
 4601            let mut auto_indent_edits = Vec::new();
 4602            let mut edits = Vec::new();
 4603            for (edit, prevent_auto_indent) in edits_with_flags {
 4604                if prevent_auto_indent {
 4605                    edits.push(edit);
 4606                } else {
 4607                    auto_indent_edits.push(edit);
 4608                }
 4609            }
 4610            if !edits.is_empty() {
 4611                this.edit(edits, cx);
 4612            }
 4613            if !auto_indent_edits.is_empty() {
 4614                this.edit_with_autoindent(auto_indent_edits, cx);
 4615            }
 4616
 4617            let buffer = this.buffer.read(cx).snapshot(cx);
 4618            let new_selections = selection_info
 4619                .into_iter()
 4620                .map(|(extra_newline_inserted, new_selection)| {
 4621                    let mut cursor = new_selection.end.to_point(&buffer);
 4622                    if extra_newline_inserted {
 4623                        cursor.row -= 1;
 4624                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4625                    }
 4626                    new_selection.map(|_| cursor)
 4627                })
 4628                .collect();
 4629
 4630            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4631            this.refresh_inline_completion(true, false, window, cx);
 4632        });
 4633    }
 4634
 4635    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4637
 4638        let buffer = self.buffer.read(cx);
 4639        let snapshot = buffer.snapshot(cx);
 4640
 4641        let mut edits = Vec::new();
 4642        let mut rows = Vec::new();
 4643
 4644        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4645            let cursor = selection.head();
 4646            let row = cursor.row;
 4647
 4648            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4649
 4650            let newline = "\n".to_string();
 4651            edits.push((start_of_line..start_of_line, newline));
 4652
 4653            rows.push(row + rows_inserted as u32);
 4654        }
 4655
 4656        self.transact(window, cx, |editor, window, cx| {
 4657            editor.edit(edits, cx);
 4658
 4659            editor.change_selections(Default::default(), window, cx, |s| {
 4660                let mut index = 0;
 4661                s.move_cursors_with(|map, _, _| {
 4662                    let row = rows[index];
 4663                    index += 1;
 4664
 4665                    let point = Point::new(row, 0);
 4666                    let boundary = map.next_line_boundary(point).1;
 4667                    let clipped = map.clip_point(boundary, Bias::Left);
 4668
 4669                    (clipped, SelectionGoal::None)
 4670                });
 4671            });
 4672
 4673            let mut indent_edits = Vec::new();
 4674            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4675            for row in rows {
 4676                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4677                for (row, indent) in indents {
 4678                    if indent.len == 0 {
 4679                        continue;
 4680                    }
 4681
 4682                    let text = match indent.kind {
 4683                        IndentKind::Space => " ".repeat(indent.len as usize),
 4684                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4685                    };
 4686                    let point = Point::new(row.0, 0);
 4687                    indent_edits.push((point..point, text));
 4688                }
 4689            }
 4690            editor.edit(indent_edits, cx);
 4691        });
 4692    }
 4693
 4694    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4696
 4697        let buffer = self.buffer.read(cx);
 4698        let snapshot = buffer.snapshot(cx);
 4699
 4700        let mut edits = Vec::new();
 4701        let mut rows = Vec::new();
 4702        let mut rows_inserted = 0;
 4703
 4704        for selection in self.selections.all_adjusted(cx) {
 4705            let cursor = selection.head();
 4706            let row = cursor.row;
 4707
 4708            let point = Point::new(row + 1, 0);
 4709            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4710
 4711            let newline = "\n".to_string();
 4712            edits.push((start_of_line..start_of_line, newline));
 4713
 4714            rows_inserted += 1;
 4715            rows.push(row + rows_inserted);
 4716        }
 4717
 4718        self.transact(window, cx, |editor, window, cx| {
 4719            editor.edit(edits, cx);
 4720
 4721            editor.change_selections(Default::default(), window, cx, |s| {
 4722                let mut index = 0;
 4723                s.move_cursors_with(|map, _, _| {
 4724                    let row = rows[index];
 4725                    index += 1;
 4726
 4727                    let point = Point::new(row, 0);
 4728                    let boundary = map.next_line_boundary(point).1;
 4729                    let clipped = map.clip_point(boundary, Bias::Left);
 4730
 4731                    (clipped, SelectionGoal::None)
 4732                });
 4733            });
 4734
 4735            let mut indent_edits = Vec::new();
 4736            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4737            for row in rows {
 4738                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4739                for (row, indent) in indents {
 4740                    if indent.len == 0 {
 4741                        continue;
 4742                    }
 4743
 4744                    let text = match indent.kind {
 4745                        IndentKind::Space => " ".repeat(indent.len as usize),
 4746                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4747                    };
 4748                    let point = Point::new(row.0, 0);
 4749                    indent_edits.push((point..point, text));
 4750                }
 4751            }
 4752            editor.edit(indent_edits, cx);
 4753        });
 4754    }
 4755
 4756    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4757        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4758            original_indent_columns: Vec::new(),
 4759        });
 4760        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4761    }
 4762
 4763    fn insert_with_autoindent_mode(
 4764        &mut self,
 4765        text: &str,
 4766        autoindent_mode: Option<AutoindentMode>,
 4767        window: &mut Window,
 4768        cx: &mut Context<Self>,
 4769    ) {
 4770        if self.read_only(cx) {
 4771            return;
 4772        }
 4773
 4774        let text: Arc<str> = text.into();
 4775        self.transact(window, cx, |this, window, cx| {
 4776            let old_selections = this.selections.all_adjusted(cx);
 4777            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4778                let anchors = {
 4779                    let snapshot = buffer.read(cx);
 4780                    old_selections
 4781                        .iter()
 4782                        .map(|s| {
 4783                            let anchor = snapshot.anchor_after(s.head());
 4784                            s.map(|_| anchor)
 4785                        })
 4786                        .collect::<Vec<_>>()
 4787                };
 4788                buffer.edit(
 4789                    old_selections
 4790                        .iter()
 4791                        .map(|s| (s.start..s.end, text.clone())),
 4792                    autoindent_mode,
 4793                    cx,
 4794                );
 4795                anchors
 4796            });
 4797
 4798            this.change_selections(Default::default(), window, cx, |s| {
 4799                s.select_anchors(selection_anchors);
 4800            });
 4801
 4802            cx.notify();
 4803        });
 4804    }
 4805
 4806    fn trigger_completion_on_input(
 4807        &mut self,
 4808        text: &str,
 4809        trigger_in_words: bool,
 4810        window: &mut Window,
 4811        cx: &mut Context<Self>,
 4812    ) {
 4813        let completions_source = self
 4814            .context_menu
 4815            .borrow()
 4816            .as_ref()
 4817            .and_then(|menu| match menu {
 4818                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4819                CodeContextMenu::CodeActions(_) => None,
 4820            });
 4821
 4822        match completions_source {
 4823            Some(CompletionsMenuSource::Words) => {
 4824                self.show_word_completions(&ShowWordCompletions, window, cx)
 4825            }
 4826            Some(CompletionsMenuSource::Normal)
 4827            | Some(CompletionsMenuSource::SnippetChoices)
 4828            | None
 4829                if self.is_completion_trigger(
 4830                    text,
 4831                    trigger_in_words,
 4832                    completions_source.is_some(),
 4833                    cx,
 4834                ) =>
 4835            {
 4836                self.show_completions(
 4837                    &ShowCompletions {
 4838                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4839                    },
 4840                    window,
 4841                    cx,
 4842                )
 4843            }
 4844            _ => {
 4845                self.hide_context_menu(window, cx);
 4846            }
 4847        }
 4848    }
 4849
 4850    fn is_completion_trigger(
 4851        &self,
 4852        text: &str,
 4853        trigger_in_words: bool,
 4854        menu_is_open: bool,
 4855        cx: &mut Context<Self>,
 4856    ) -> bool {
 4857        let position = self.selections.newest_anchor().head();
 4858        let multibuffer = self.buffer.read(cx);
 4859        let Some(buffer) = position
 4860            .buffer_id
 4861            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4862        else {
 4863            return false;
 4864        };
 4865
 4866        if let Some(completion_provider) = &self.completion_provider {
 4867            completion_provider.is_completion_trigger(
 4868                &buffer,
 4869                position.text_anchor,
 4870                text,
 4871                trigger_in_words,
 4872                menu_is_open,
 4873                cx,
 4874            )
 4875        } else {
 4876            false
 4877        }
 4878    }
 4879
 4880    /// If any empty selections is touching the start of its innermost containing autoclose
 4881    /// region, expand it to select the brackets.
 4882    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4883        let selections = self.selections.all::<usize>(cx);
 4884        let buffer = self.buffer.read(cx).read(cx);
 4885        let new_selections = self
 4886            .selections_with_autoclose_regions(selections, &buffer)
 4887            .map(|(mut selection, region)| {
 4888                if !selection.is_empty() {
 4889                    return selection;
 4890                }
 4891
 4892                if let Some(region) = region {
 4893                    let mut range = region.range.to_offset(&buffer);
 4894                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4895                        range.start -= region.pair.start.len();
 4896                        if buffer.contains_str_at(range.start, &region.pair.start)
 4897                            && buffer.contains_str_at(range.end, &region.pair.end)
 4898                        {
 4899                            range.end += region.pair.end.len();
 4900                            selection.start = range.start;
 4901                            selection.end = range.end;
 4902
 4903                            return selection;
 4904                        }
 4905                    }
 4906                }
 4907
 4908                let always_treat_brackets_as_autoclosed = buffer
 4909                    .language_settings_at(selection.start, cx)
 4910                    .always_treat_brackets_as_autoclosed;
 4911
 4912                if !always_treat_brackets_as_autoclosed {
 4913                    return selection;
 4914                }
 4915
 4916                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4917                    for (pair, enabled) in scope.brackets() {
 4918                        if !enabled || !pair.close {
 4919                            continue;
 4920                        }
 4921
 4922                        if buffer.contains_str_at(selection.start, &pair.end) {
 4923                            let pair_start_len = pair.start.len();
 4924                            if buffer.contains_str_at(
 4925                                selection.start.saturating_sub(pair_start_len),
 4926                                &pair.start,
 4927                            ) {
 4928                                selection.start -= pair_start_len;
 4929                                selection.end += pair.end.len();
 4930
 4931                                return selection;
 4932                            }
 4933                        }
 4934                    }
 4935                }
 4936
 4937                selection
 4938            })
 4939            .collect();
 4940
 4941        drop(buffer);
 4942        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4943            selections.select(new_selections)
 4944        });
 4945    }
 4946
 4947    /// Iterate the given selections, and for each one, find the smallest surrounding
 4948    /// autoclose region. This uses the ordering of the selections and the autoclose
 4949    /// regions to avoid repeated comparisons.
 4950    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4951        &'a self,
 4952        selections: impl IntoIterator<Item = Selection<D>>,
 4953        buffer: &'a MultiBufferSnapshot,
 4954    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4955        let mut i = 0;
 4956        let mut regions = self.autoclose_regions.as_slice();
 4957        selections.into_iter().map(move |selection| {
 4958            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4959
 4960            let mut enclosing = None;
 4961            while let Some(pair_state) = regions.get(i) {
 4962                if pair_state.range.end.to_offset(buffer) < range.start {
 4963                    regions = &regions[i + 1..];
 4964                    i = 0;
 4965                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4966                    break;
 4967                } else {
 4968                    if pair_state.selection_id == selection.id {
 4969                        enclosing = Some(pair_state);
 4970                    }
 4971                    i += 1;
 4972                }
 4973            }
 4974
 4975            (selection, enclosing)
 4976        })
 4977    }
 4978
 4979    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4980    fn invalidate_autoclose_regions(
 4981        &mut self,
 4982        mut selections: &[Selection<Anchor>],
 4983        buffer: &MultiBufferSnapshot,
 4984    ) {
 4985        self.autoclose_regions.retain(|state| {
 4986            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4987                return false;
 4988            }
 4989
 4990            let mut i = 0;
 4991            while let Some(selection) = selections.get(i) {
 4992                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4993                    selections = &selections[1..];
 4994                    continue;
 4995                }
 4996                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4997                    break;
 4998                }
 4999                if selection.id == state.selection_id {
 5000                    return true;
 5001                } else {
 5002                    i += 1;
 5003                }
 5004            }
 5005            false
 5006        });
 5007    }
 5008
 5009    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5010        let offset = position.to_offset(buffer);
 5011        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5012        if offset > word_range.start && kind == Some(CharKind::Word) {
 5013            Some(
 5014                buffer
 5015                    .text_for_range(word_range.start..offset)
 5016                    .collect::<String>(),
 5017            )
 5018        } else {
 5019            None
 5020        }
 5021    }
 5022
 5023    pub fn toggle_inline_values(
 5024        &mut self,
 5025        _: &ToggleInlineValues,
 5026        _: &mut Window,
 5027        cx: &mut Context<Self>,
 5028    ) {
 5029        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5030
 5031        self.refresh_inline_values(cx);
 5032    }
 5033
 5034    pub fn toggle_inlay_hints(
 5035        &mut self,
 5036        _: &ToggleInlayHints,
 5037        _: &mut Window,
 5038        cx: &mut Context<Self>,
 5039    ) {
 5040        self.refresh_inlay_hints(
 5041            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5042            cx,
 5043        );
 5044    }
 5045
 5046    pub fn inlay_hints_enabled(&self) -> bool {
 5047        self.inlay_hint_cache.enabled
 5048    }
 5049
 5050    pub fn inline_values_enabled(&self) -> bool {
 5051        self.inline_value_cache.enabled
 5052    }
 5053
 5054    #[cfg(any(test, feature = "test-support"))]
 5055    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5056        self.display_map
 5057            .read(cx)
 5058            .current_inlays()
 5059            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5060            .cloned()
 5061            .collect()
 5062    }
 5063
 5064    #[cfg(any(test, feature = "test-support"))]
 5065    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5066        self.display_map
 5067            .read(cx)
 5068            .current_inlays()
 5069            .cloned()
 5070            .collect()
 5071    }
 5072
 5073    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5074        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5075            return;
 5076        }
 5077
 5078        let reason_description = reason.description();
 5079        let ignore_debounce = matches!(
 5080            reason,
 5081            InlayHintRefreshReason::SettingsChange(_)
 5082                | InlayHintRefreshReason::Toggle(_)
 5083                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5084                | InlayHintRefreshReason::ModifiersChanged(_)
 5085        );
 5086        let (invalidate_cache, required_languages) = match reason {
 5087            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5088                match self.inlay_hint_cache.modifiers_override(enabled) {
 5089                    Some(enabled) => {
 5090                        if enabled {
 5091                            (InvalidationStrategy::RefreshRequested, None)
 5092                        } else {
 5093                            self.splice_inlays(
 5094                                &self
 5095                                    .visible_inlay_hints(cx)
 5096                                    .iter()
 5097                                    .map(|inlay| inlay.id)
 5098                                    .collect::<Vec<InlayId>>(),
 5099                                Vec::new(),
 5100                                cx,
 5101                            );
 5102                            return;
 5103                        }
 5104                    }
 5105                    None => return,
 5106                }
 5107            }
 5108            InlayHintRefreshReason::Toggle(enabled) => {
 5109                if self.inlay_hint_cache.toggle(enabled) {
 5110                    if enabled {
 5111                        (InvalidationStrategy::RefreshRequested, None)
 5112                    } else {
 5113                        self.splice_inlays(
 5114                            &self
 5115                                .visible_inlay_hints(cx)
 5116                                .iter()
 5117                                .map(|inlay| inlay.id)
 5118                                .collect::<Vec<InlayId>>(),
 5119                            Vec::new(),
 5120                            cx,
 5121                        );
 5122                        return;
 5123                    }
 5124                } else {
 5125                    return;
 5126                }
 5127            }
 5128            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5129                match self.inlay_hint_cache.update_settings(
 5130                    &self.buffer,
 5131                    new_settings,
 5132                    self.visible_inlay_hints(cx),
 5133                    cx,
 5134                ) {
 5135                    ControlFlow::Break(Some(InlaySplice {
 5136                        to_remove,
 5137                        to_insert,
 5138                    })) => {
 5139                        self.splice_inlays(&to_remove, to_insert, cx);
 5140                        return;
 5141                    }
 5142                    ControlFlow::Break(None) => return,
 5143                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5144                }
 5145            }
 5146            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5147                if let Some(InlaySplice {
 5148                    to_remove,
 5149                    to_insert,
 5150                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5151                {
 5152                    self.splice_inlays(&to_remove, to_insert, cx);
 5153                }
 5154                self.display_map.update(cx, |display_map, _| {
 5155                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5156                });
 5157                return;
 5158            }
 5159            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5160            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5161                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5162            }
 5163            InlayHintRefreshReason::RefreshRequested => {
 5164                (InvalidationStrategy::RefreshRequested, None)
 5165            }
 5166        };
 5167
 5168        if let Some(InlaySplice {
 5169            to_remove,
 5170            to_insert,
 5171        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5172            reason_description,
 5173            self.visible_excerpts(required_languages.as_ref(), cx),
 5174            invalidate_cache,
 5175            ignore_debounce,
 5176            cx,
 5177        ) {
 5178            self.splice_inlays(&to_remove, to_insert, cx);
 5179        }
 5180    }
 5181
 5182    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5183        self.display_map
 5184            .read(cx)
 5185            .current_inlays()
 5186            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    pub fn visible_excerpts(
 5192        &self,
 5193        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5194        cx: &mut Context<Editor>,
 5195    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5196        let Some(project) = self.project.as_ref() else {
 5197            return HashMap::default();
 5198        };
 5199        let project = project.read(cx);
 5200        let multi_buffer = self.buffer().read(cx);
 5201        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5202        let multi_buffer_visible_start = self
 5203            .scroll_manager
 5204            .anchor()
 5205            .anchor
 5206            .to_point(&multi_buffer_snapshot);
 5207        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5208            multi_buffer_visible_start
 5209                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5210            Bias::Left,
 5211        );
 5212        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5213        multi_buffer_snapshot
 5214            .range_to_buffer_ranges(multi_buffer_visible_range)
 5215            .into_iter()
 5216            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5217            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5218                let buffer_file = project::File::from_dyn(buffer.file())?;
 5219                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5220                let worktree_entry = buffer_worktree
 5221                    .read(cx)
 5222                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5223                if worktree_entry.is_ignored {
 5224                    return None;
 5225                }
 5226
 5227                let language = buffer.language()?;
 5228                if let Some(restrict_to_languages) = restrict_to_languages {
 5229                    if !restrict_to_languages.contains(language) {
 5230                        return None;
 5231                    }
 5232                }
 5233                Some((
 5234                    excerpt_id,
 5235                    (
 5236                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5237                        buffer.version().clone(),
 5238                        excerpt_visible_range,
 5239                    ),
 5240                ))
 5241            })
 5242            .collect()
 5243    }
 5244
 5245    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5246        TextLayoutDetails {
 5247            text_system: window.text_system().clone(),
 5248            editor_style: self.style.clone().unwrap(),
 5249            rem_size: window.rem_size(),
 5250            scroll_anchor: self.scroll_manager.anchor(),
 5251            visible_rows: self.visible_line_count(),
 5252            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5253        }
 5254    }
 5255
 5256    pub fn splice_inlays(
 5257        &self,
 5258        to_remove: &[InlayId],
 5259        to_insert: Vec<Inlay>,
 5260        cx: &mut Context<Self>,
 5261    ) {
 5262        self.display_map.update(cx, |display_map, cx| {
 5263            display_map.splice_inlays(to_remove, to_insert, cx)
 5264        });
 5265        cx.notify();
 5266    }
 5267
 5268    fn trigger_on_type_formatting(
 5269        &self,
 5270        input: String,
 5271        window: &mut Window,
 5272        cx: &mut Context<Self>,
 5273    ) -> Option<Task<Result<()>>> {
 5274        if input.len() != 1 {
 5275            return None;
 5276        }
 5277
 5278        let project = self.project.as_ref()?;
 5279        let position = self.selections.newest_anchor().head();
 5280        let (buffer, buffer_position) = self
 5281            .buffer
 5282            .read(cx)
 5283            .text_anchor_for_position(position, cx)?;
 5284
 5285        let settings = language_settings::language_settings(
 5286            buffer
 5287                .read(cx)
 5288                .language_at(buffer_position)
 5289                .map(|l| l.name()),
 5290            buffer.read(cx).file(),
 5291            cx,
 5292        );
 5293        if !settings.use_on_type_format {
 5294            return None;
 5295        }
 5296
 5297        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5298        // hence we do LSP request & edit on host side only — add formats to host's history.
 5299        let push_to_lsp_host_history = true;
 5300        // If this is not the host, append its history with new edits.
 5301        let push_to_client_history = project.read(cx).is_via_collab();
 5302
 5303        let on_type_formatting = project.update(cx, |project, cx| {
 5304            project.on_type_format(
 5305                buffer.clone(),
 5306                buffer_position,
 5307                input,
 5308                push_to_lsp_host_history,
 5309                cx,
 5310            )
 5311        });
 5312        Some(cx.spawn_in(window, async move |editor, cx| {
 5313            if let Some(transaction) = on_type_formatting.await? {
 5314                if push_to_client_history {
 5315                    buffer
 5316                        .update(cx, |buffer, _| {
 5317                            buffer.push_transaction(transaction, Instant::now());
 5318                            buffer.finalize_last_transaction();
 5319                        })
 5320                        .ok();
 5321                }
 5322                editor.update(cx, |editor, cx| {
 5323                    editor.refresh_document_highlights(cx);
 5324                })?;
 5325            }
 5326            Ok(())
 5327        }))
 5328    }
 5329
 5330    pub fn show_word_completions(
 5331        &mut self,
 5332        _: &ShowWordCompletions,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5337    }
 5338
 5339    pub fn show_completions(
 5340        &mut self,
 5341        options: &ShowCompletions,
 5342        window: &mut Window,
 5343        cx: &mut Context<Self>,
 5344    ) {
 5345        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5346    }
 5347
 5348    fn open_or_update_completions_menu(
 5349        &mut self,
 5350        requested_source: Option<CompletionsMenuSource>,
 5351        trigger: Option<&str>,
 5352        window: &mut Window,
 5353        cx: &mut Context<Self>,
 5354    ) {
 5355        if self.pending_rename.is_some() {
 5356            return;
 5357        }
 5358
 5359        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5360
 5361        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5362        // inserted and selected. To handle that case, the start of the selection is used so that
 5363        // the menu starts with all choices.
 5364        let position = self
 5365            .selections
 5366            .newest_anchor()
 5367            .start
 5368            .bias_right(&multibuffer_snapshot);
 5369        if position.diff_base_anchor.is_some() {
 5370            return;
 5371        }
 5372        let (buffer, buffer_position) =
 5373            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5374                output
 5375            } else {
 5376                return;
 5377            };
 5378        let buffer_snapshot = buffer.read(cx).snapshot();
 5379
 5380        let query: Option<Arc<String>> =
 5381            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5382
 5383        drop(multibuffer_snapshot);
 5384
 5385        let provider = match requested_source {
 5386            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5387            Some(CompletionsMenuSource::Words) => None,
 5388            Some(CompletionsMenuSource::SnippetChoices) => {
 5389                log::error!("bug: SnippetChoices requested_source is not handled");
 5390                None
 5391            }
 5392        };
 5393
 5394        let sort_completions = provider
 5395            .as_ref()
 5396            .map_or(false, |provider| provider.sort_completions());
 5397
 5398        let filter_completions = provider
 5399            .as_ref()
 5400            .map_or(true, |provider| provider.filter_completions());
 5401
 5402        let trigger_kind = match trigger {
 5403            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5404                CompletionTriggerKind::TRIGGER_CHARACTER
 5405            }
 5406            _ => CompletionTriggerKind::INVOKED,
 5407        };
 5408        let completion_context = CompletionContext {
 5409            trigger_character: trigger.and_then(|trigger| {
 5410                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5411                    Some(String::from(trigger))
 5412                } else {
 5413                    None
 5414                }
 5415            }),
 5416            trigger_kind,
 5417        };
 5418
 5419        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5420        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5421        // involve trigger chars, so this is skipped in that case.
 5422        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5423        {
 5424            let menu_is_open = matches!(
 5425                self.context_menu.borrow().as_ref(),
 5426                Some(CodeContextMenu::Completions(_))
 5427            );
 5428            if menu_is_open {
 5429                self.hide_context_menu(window, cx);
 5430            }
 5431        }
 5432
 5433        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5434            if filter_completions {
 5435                menu.filter(query.clone(), provider.clone(), window, cx);
 5436            }
 5437            // When `is_incomplete` is false, no need to re-query completions when the current query
 5438            // is a suffix of the initial query.
 5439            if !menu.is_incomplete {
 5440                // If the new query is a suffix of the old query (typing more characters) and
 5441                // the previous result was complete, the existing completions can be filtered.
 5442                //
 5443                // Note that this is always true for snippet completions.
 5444                let query_matches = match (&menu.initial_query, &query) {
 5445                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5446                    (None, _) => true,
 5447                    _ => false,
 5448                };
 5449                if query_matches {
 5450                    let position_matches = if menu.initial_position == position {
 5451                        true
 5452                    } else {
 5453                        let snapshot = self.buffer.read(cx).read(cx);
 5454                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5455                    };
 5456                    if position_matches {
 5457                        return;
 5458                    }
 5459                }
 5460            }
 5461        };
 5462
 5463        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5464            buffer_snapshot.surrounding_word(buffer_position, false)
 5465        {
 5466            let word_to_exclude = buffer_snapshot
 5467                .text_for_range(word_range.clone())
 5468                .collect::<String>();
 5469            (
 5470                buffer_snapshot.anchor_before(word_range.start)
 5471                    ..buffer_snapshot.anchor_after(buffer_position),
 5472                Some(word_to_exclude),
 5473            )
 5474        } else {
 5475            (buffer_position..buffer_position, None)
 5476        };
 5477
 5478        let language = buffer_snapshot
 5479            .language_at(buffer_position)
 5480            .map(|language| language.name());
 5481
 5482        let completion_settings =
 5483            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5484
 5485        let show_completion_documentation = buffer_snapshot
 5486            .settings_at(buffer_position, cx)
 5487            .show_completion_documentation;
 5488
 5489        // The document can be large, so stay in reasonable bounds when searching for words,
 5490        // otherwise completion pop-up might be slow to appear.
 5491        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5492        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5493        let min_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5495            Bias::Left,
 5496        );
 5497        let max_word_search = buffer_snapshot.clip_point(
 5498            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5499            Bias::Right,
 5500        );
 5501        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5502            ..buffer_snapshot.point_to_offset(max_word_search);
 5503
 5504        let skip_digits = query
 5505            .as_ref()
 5506            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5507
 5508        let (mut words, provider_responses) = match &provider {
 5509            Some(provider) => {
 5510                let provider_responses = provider.completions(
 5511                    position.excerpt_id,
 5512                    &buffer,
 5513                    buffer_position,
 5514                    completion_context,
 5515                    window,
 5516                    cx,
 5517                );
 5518
 5519                let words = match completion_settings.words {
 5520                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5521                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5522                        .background_spawn(async move {
 5523                            buffer_snapshot.words_in_range(WordsQuery {
 5524                                fuzzy_contents: None,
 5525                                range: word_search_range,
 5526                                skip_digits,
 5527                            })
 5528                        }),
 5529                };
 5530
 5531                (words, provider_responses)
 5532            }
 5533            None => (
 5534                cx.background_spawn(async move {
 5535                    buffer_snapshot.words_in_range(WordsQuery {
 5536                        fuzzy_contents: None,
 5537                        range: word_search_range,
 5538                        skip_digits,
 5539                    })
 5540                }),
 5541                Task::ready(Ok(Vec::new())),
 5542            ),
 5543        };
 5544
 5545        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5546
 5547        let id = post_inc(&mut self.next_completion_id);
 5548        let task = cx.spawn_in(window, async move |editor, cx| {
 5549            let Ok(()) = editor.update(cx, |this, _| {
 5550                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5551            }) else {
 5552                return;
 5553            };
 5554
 5555            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5556            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5557            let mut completions = Vec::new();
 5558            let mut is_incomplete = false;
 5559            if let Some(provider_responses) = provider_responses.await.log_err() {
 5560                if !provider_responses.is_empty() {
 5561                    for response in provider_responses {
 5562                        completions.extend(response.completions);
 5563                        is_incomplete = is_incomplete || response.is_incomplete;
 5564                    }
 5565                    if completion_settings.words == WordsCompletionMode::Fallback {
 5566                        words = Task::ready(BTreeMap::default());
 5567                    }
 5568                }
 5569            }
 5570
 5571            let mut words = words.await;
 5572            if let Some(word_to_exclude) = &word_to_exclude {
 5573                words.remove(word_to_exclude);
 5574            }
 5575            for lsp_completion in &completions {
 5576                words.remove(&lsp_completion.new_text);
 5577            }
 5578            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5579                replace_range: word_replace_range.clone(),
 5580                new_text: word.clone(),
 5581                label: CodeLabel::plain(word, None),
 5582                icon_path: None,
 5583                documentation: None,
 5584                source: CompletionSource::BufferWord {
 5585                    word_range,
 5586                    resolved: false,
 5587                },
 5588                insert_text_mode: Some(InsertTextMode::AS_IS),
 5589                confirm: None,
 5590            }));
 5591
 5592            let menu = if completions.is_empty() {
 5593                None
 5594            } else {
 5595                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5596                    let languages = editor
 5597                        .workspace
 5598                        .as_ref()
 5599                        .and_then(|(workspace, _)| workspace.upgrade())
 5600                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5601                    let menu = CompletionsMenu::new(
 5602                        id,
 5603                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5604                        sort_completions,
 5605                        show_completion_documentation,
 5606                        position,
 5607                        query.clone(),
 5608                        is_incomplete,
 5609                        buffer.clone(),
 5610                        completions.into(),
 5611                        snippet_sort_order,
 5612                        languages,
 5613                        language,
 5614                        cx,
 5615                    );
 5616
 5617                    let query = if filter_completions { query } else { None };
 5618                    let matches_task = if let Some(query) = query {
 5619                        menu.do_async_filtering(query, cx)
 5620                    } else {
 5621                        Task::ready(menu.unfiltered_matches())
 5622                    };
 5623                    (menu, matches_task)
 5624                }) else {
 5625                    return;
 5626                };
 5627
 5628                let matches = matches_task.await;
 5629
 5630                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5631                    // Newer menu already set, so exit.
 5632                    match editor.context_menu.borrow().as_ref() {
 5633                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5634                            if prev_menu.id > id {
 5635                                return;
 5636                            }
 5637                        }
 5638                        _ => {}
 5639                    };
 5640
 5641                    // Only valid to take prev_menu because it the new menu is immediately set
 5642                    // below, or the menu is hidden.
 5643                    match editor.context_menu.borrow_mut().take() {
 5644                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5645                            let position_matches =
 5646                                if prev_menu.initial_position == menu.initial_position {
 5647                                    true
 5648                                } else {
 5649                                    let snapshot = editor.buffer.read(cx).read(cx);
 5650                                    prev_menu.initial_position.to_offset(&snapshot)
 5651                                        == menu.initial_position.to_offset(&snapshot)
 5652                                };
 5653                            if position_matches {
 5654                                // Preserve markdown cache before `set_filter_results` because it will
 5655                                // try to populate the documentation cache.
 5656                                menu.preserve_markdown_cache(prev_menu);
 5657                            }
 5658                        }
 5659                        _ => {}
 5660                    };
 5661
 5662                    menu.set_filter_results(matches, provider, window, cx);
 5663                }) else {
 5664                    return;
 5665                };
 5666
 5667                menu.visible().then_some(menu)
 5668            };
 5669
 5670            editor
 5671                .update_in(cx, |editor, window, cx| {
 5672                    if editor.focus_handle.is_focused(window) {
 5673                        if let Some(menu) = menu {
 5674                            *editor.context_menu.borrow_mut() =
 5675                                Some(CodeContextMenu::Completions(menu));
 5676
 5677                            crate::hover_popover::hide_hover(editor, cx);
 5678                            if editor.show_edit_predictions_in_menu() {
 5679                                editor.update_visible_inline_completion(window, cx);
 5680                            } else {
 5681                                editor.discard_inline_completion(false, cx);
 5682                            }
 5683
 5684                            cx.notify();
 5685                            return;
 5686                        }
 5687                    }
 5688
 5689                    if editor.completion_tasks.len() <= 1 {
 5690                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5691                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5692                        // If it was already hidden and we don't show inline completions in the menu, we should
 5693                        // also show the inline-completion when available.
 5694                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5695                            editor.update_visible_inline_completion(window, cx);
 5696                        }
 5697                    }
 5698                })
 5699                .ok();
 5700        });
 5701
 5702        self.completion_tasks.push((id, task));
 5703    }
 5704
 5705    #[cfg(feature = "test-support")]
 5706    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5707        let menu = self.context_menu.borrow();
 5708        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5709            let completions = menu.completions.borrow();
 5710            Some(completions.to_vec())
 5711        } else {
 5712            None
 5713        }
 5714    }
 5715
 5716    pub fn with_completions_menu_matching_id<R>(
 5717        &self,
 5718        id: CompletionId,
 5719        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5720    ) -> R {
 5721        let mut context_menu = self.context_menu.borrow_mut();
 5722        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5723            return f(None);
 5724        };
 5725        if completions_menu.id != id {
 5726            return f(None);
 5727        }
 5728        f(Some(completions_menu))
 5729    }
 5730
 5731    pub fn confirm_completion(
 5732        &mut self,
 5733        action: &ConfirmCompletion,
 5734        window: &mut Window,
 5735        cx: &mut Context<Self>,
 5736    ) -> Option<Task<Result<()>>> {
 5737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5738        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5739    }
 5740
 5741    pub fn confirm_completion_insert(
 5742        &mut self,
 5743        _: &ConfirmCompletionInsert,
 5744        window: &mut Window,
 5745        cx: &mut Context<Self>,
 5746    ) -> Option<Task<Result<()>>> {
 5747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5748        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5749    }
 5750
 5751    pub fn confirm_completion_replace(
 5752        &mut self,
 5753        _: &ConfirmCompletionReplace,
 5754        window: &mut Window,
 5755        cx: &mut Context<Self>,
 5756    ) -> Option<Task<Result<()>>> {
 5757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5758        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5759    }
 5760
 5761    pub fn compose_completion(
 5762        &mut self,
 5763        action: &ComposeCompletion,
 5764        window: &mut Window,
 5765        cx: &mut Context<Self>,
 5766    ) -> Option<Task<Result<()>>> {
 5767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5768        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5769    }
 5770
 5771    fn do_completion(
 5772        &mut self,
 5773        item_ix: Option<usize>,
 5774        intent: CompletionIntent,
 5775        window: &mut Window,
 5776        cx: &mut Context<Editor>,
 5777    ) -> Option<Task<Result<()>>> {
 5778        use language::ToOffset as _;
 5779
 5780        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5781        else {
 5782            return None;
 5783        };
 5784
 5785        let candidate_id = {
 5786            let entries = completions_menu.entries.borrow();
 5787            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5788            if self.show_edit_predictions_in_menu() {
 5789                self.discard_inline_completion(true, cx);
 5790            }
 5791            mat.candidate_id
 5792        };
 5793
 5794        let completion = completions_menu
 5795            .completions
 5796            .borrow()
 5797            .get(candidate_id)?
 5798            .clone();
 5799        cx.stop_propagation();
 5800
 5801        let buffer_handle = completions_menu.buffer.clone();
 5802
 5803        let CompletionEdit {
 5804            new_text,
 5805            snippet,
 5806            replace_range,
 5807        } = process_completion_for_edit(
 5808            &completion,
 5809            intent,
 5810            &buffer_handle,
 5811            &completions_menu.initial_position.text_anchor,
 5812            cx,
 5813        );
 5814
 5815        let buffer = buffer_handle.read(cx);
 5816        let snapshot = self.buffer.read(cx).snapshot(cx);
 5817        let newest_anchor = self.selections.newest_anchor();
 5818        let replace_range_multibuffer = {
 5819            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5820            let multibuffer_anchor = snapshot
 5821                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5822                .unwrap()
 5823                ..snapshot
 5824                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5825                    .unwrap();
 5826            multibuffer_anchor.start.to_offset(&snapshot)
 5827                ..multibuffer_anchor.end.to_offset(&snapshot)
 5828        };
 5829        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5830            return None;
 5831        }
 5832
 5833        let old_text = buffer
 5834            .text_for_range(replace_range.clone())
 5835            .collect::<String>();
 5836        let lookbehind = newest_anchor
 5837            .start
 5838            .text_anchor
 5839            .to_offset(buffer)
 5840            .saturating_sub(replace_range.start);
 5841        let lookahead = replace_range
 5842            .end
 5843            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5844        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5845        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5846
 5847        let selections = self.selections.all::<usize>(cx);
 5848        let mut ranges = Vec::new();
 5849        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5850
 5851        for selection in &selections {
 5852            let range = if selection.id == newest_anchor.id {
 5853                replace_range_multibuffer.clone()
 5854            } else {
 5855                let mut range = selection.range();
 5856
 5857                // if prefix is present, don't duplicate it
 5858                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5859                    range.start = range.start.saturating_sub(lookbehind);
 5860
 5861                    // if suffix is also present, mimic the newest cursor and replace it
 5862                    if selection.id != newest_anchor.id
 5863                        && snapshot.contains_str_at(range.end, suffix)
 5864                    {
 5865                        range.end += lookahead;
 5866                    }
 5867                }
 5868                range
 5869            };
 5870
 5871            ranges.push(range.clone());
 5872
 5873            if !self.linked_edit_ranges.is_empty() {
 5874                let start_anchor = snapshot.anchor_before(range.start);
 5875                let end_anchor = snapshot.anchor_after(range.end);
 5876                if let Some(ranges) = self
 5877                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5878                {
 5879                    for (buffer, edits) in ranges {
 5880                        linked_edits
 5881                            .entry(buffer.clone())
 5882                            .or_default()
 5883                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5884                    }
 5885                }
 5886            }
 5887        }
 5888
 5889        let common_prefix_len = old_text
 5890            .chars()
 5891            .zip(new_text.chars())
 5892            .take_while(|(a, b)| a == b)
 5893            .map(|(a, _)| a.len_utf8())
 5894            .sum::<usize>();
 5895
 5896        cx.emit(EditorEvent::InputHandled {
 5897            utf16_range_to_replace: None,
 5898            text: new_text[common_prefix_len..].into(),
 5899        });
 5900
 5901        self.transact(window, cx, |editor, window, cx| {
 5902            if let Some(mut snippet) = snippet {
 5903                snippet.text = new_text.to_string();
 5904                editor
 5905                    .insert_snippet(&ranges, snippet, window, cx)
 5906                    .log_err();
 5907            } else {
 5908                editor.buffer.update(cx, |multi_buffer, cx| {
 5909                    let auto_indent = match completion.insert_text_mode {
 5910                        Some(InsertTextMode::AS_IS) => None,
 5911                        _ => editor.autoindent_mode.clone(),
 5912                    };
 5913                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5914                    multi_buffer.edit(edits, auto_indent, cx);
 5915                });
 5916            }
 5917            for (buffer, edits) in linked_edits {
 5918                buffer.update(cx, |buffer, cx| {
 5919                    let snapshot = buffer.snapshot();
 5920                    let edits = edits
 5921                        .into_iter()
 5922                        .map(|(range, text)| {
 5923                            use text::ToPoint as TP;
 5924                            let end_point = TP::to_point(&range.end, &snapshot);
 5925                            let start_point = TP::to_point(&range.start, &snapshot);
 5926                            (start_point..end_point, text)
 5927                        })
 5928                        .sorted_by_key(|(range, _)| range.start);
 5929                    buffer.edit(edits, None, cx);
 5930                })
 5931            }
 5932
 5933            editor.refresh_inline_completion(true, false, window, cx);
 5934        });
 5935        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5936
 5937        let show_new_completions_on_confirm = completion
 5938            .confirm
 5939            .as_ref()
 5940            .map_or(false, |confirm| confirm(intent, window, cx));
 5941        if show_new_completions_on_confirm {
 5942            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5943        }
 5944
 5945        let provider = self.completion_provider.as_ref()?;
 5946        drop(completion);
 5947        let apply_edits = provider.apply_additional_edits_for_completion(
 5948            buffer_handle,
 5949            completions_menu.completions.clone(),
 5950            candidate_id,
 5951            true,
 5952            cx,
 5953        );
 5954
 5955        let editor_settings = EditorSettings::get_global(cx);
 5956        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5957            // After the code completion is finished, users often want to know what signatures are needed.
 5958            // so we should automatically call signature_help
 5959            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5960        }
 5961
 5962        Some(cx.foreground_executor().spawn(async move {
 5963            apply_edits.await?;
 5964            Ok(())
 5965        }))
 5966    }
 5967
 5968    pub fn toggle_code_actions(
 5969        &mut self,
 5970        action: &ToggleCodeActions,
 5971        window: &mut Window,
 5972        cx: &mut Context<Self>,
 5973    ) {
 5974        let quick_launch = action.quick_launch;
 5975        let mut context_menu = self.context_menu.borrow_mut();
 5976        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5977            if code_actions.deployed_from == action.deployed_from {
 5978                // Toggle if we're selecting the same one
 5979                *context_menu = None;
 5980                cx.notify();
 5981                return;
 5982            } else {
 5983                // Otherwise, clear it and start a new one
 5984                *context_menu = None;
 5985                cx.notify();
 5986            }
 5987        }
 5988        drop(context_menu);
 5989        let snapshot = self.snapshot(window, cx);
 5990        let deployed_from = action.deployed_from.clone();
 5991        let action = action.clone();
 5992        self.completion_tasks.clear();
 5993        self.discard_inline_completion(false, cx);
 5994
 5995        let multibuffer_point = match &action.deployed_from {
 5996            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5997                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5998            }
 5999            _ => self.selections.newest::<Point>(cx).head(),
 6000        };
 6001        let Some((buffer, buffer_row)) = snapshot
 6002            .buffer_snapshot
 6003            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6004            .and_then(|(buffer_snapshot, range)| {
 6005                self.buffer()
 6006                    .read(cx)
 6007                    .buffer(buffer_snapshot.remote_id())
 6008                    .map(|buffer| (buffer, range.start.row))
 6009            })
 6010        else {
 6011            return;
 6012        };
 6013        let buffer_id = buffer.read(cx).remote_id();
 6014        let tasks = self
 6015            .tasks
 6016            .get(&(buffer_id, buffer_row))
 6017            .map(|t| Arc::new(t.to_owned()));
 6018
 6019        if !self.focus_handle.is_focused(window) {
 6020            return;
 6021        }
 6022        let project = self.project.clone();
 6023
 6024        let code_actions_task = match deployed_from {
 6025            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6026            _ => self.code_actions(buffer_row, window, cx),
 6027        };
 6028
 6029        let runnable_task = match deployed_from {
 6030            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6031            _ => {
 6032                let mut task_context_task = Task::ready(None);
 6033                if let Some(tasks) = &tasks {
 6034                    if let Some(project) = project {
 6035                        task_context_task =
 6036                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6037                    }
 6038                }
 6039
 6040                cx.spawn_in(window, {
 6041                    let buffer = buffer.clone();
 6042                    async move |editor, cx| {
 6043                        let task_context = task_context_task.await;
 6044
 6045                        let resolved_tasks =
 6046                            tasks
 6047                                .zip(task_context.clone())
 6048                                .map(|(tasks, task_context)| ResolvedTasks {
 6049                                    templates: tasks.resolve(&task_context).collect(),
 6050                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6051                                        multibuffer_point.row,
 6052                                        tasks.column,
 6053                                    )),
 6054                                });
 6055                        let debug_scenarios = editor
 6056                            .update(cx, |editor, cx| {
 6057                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6058                            })?
 6059                            .await;
 6060                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6061                    }
 6062                })
 6063            }
 6064        };
 6065
 6066        cx.spawn_in(window, async move |editor, cx| {
 6067            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6068            let code_actions = code_actions_task.await;
 6069            let spawn_straight_away = quick_launch
 6070                && resolved_tasks
 6071                    .as_ref()
 6072                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6073                && code_actions
 6074                    .as_ref()
 6075                    .map_or(true, |actions| actions.is_empty())
 6076                && debug_scenarios.is_empty();
 6077
 6078            editor.update_in(cx, |editor, window, cx| {
 6079                crate::hover_popover::hide_hover(editor, cx);
 6080                let actions = CodeActionContents::new(
 6081                    resolved_tasks,
 6082                    code_actions,
 6083                    debug_scenarios,
 6084                    task_context.unwrap_or_default(),
 6085                );
 6086
 6087                // Don't show the menu if there are no actions available
 6088                if actions.is_empty() {
 6089                    cx.notify();
 6090                    return Task::ready(Ok(()));
 6091                }
 6092
 6093                *editor.context_menu.borrow_mut() =
 6094                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6095                        buffer,
 6096                        actions,
 6097                        selected_item: Default::default(),
 6098                        scroll_handle: UniformListScrollHandle::default(),
 6099                        deployed_from,
 6100                    }));
 6101                cx.notify();
 6102                if spawn_straight_away {
 6103                    if let Some(task) = editor.confirm_code_action(
 6104                        &ConfirmCodeAction { item_ix: Some(0) },
 6105                        window,
 6106                        cx,
 6107                    ) {
 6108                        return task;
 6109                    }
 6110                }
 6111
 6112                Task::ready(Ok(()))
 6113            })
 6114        })
 6115        .detach_and_log_err(cx);
 6116    }
 6117
 6118    fn debug_scenarios(
 6119        &mut self,
 6120        resolved_tasks: &Option<ResolvedTasks>,
 6121        buffer: &Entity<Buffer>,
 6122        cx: &mut App,
 6123    ) -> Task<Vec<task::DebugScenario>> {
 6124        maybe!({
 6125            let project = self.project.as_ref()?;
 6126            let dap_store = project.read(cx).dap_store();
 6127            let mut scenarios = vec![];
 6128            let resolved_tasks = resolved_tasks.as_ref()?;
 6129            let buffer = buffer.read(cx);
 6130            let language = buffer.language()?;
 6131            let file = buffer.file();
 6132            let debug_adapter = language_settings(language.name().into(), file, cx)
 6133                .debuggers
 6134                .first()
 6135                .map(SharedString::from)
 6136                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6137
 6138            dap_store.update(cx, |dap_store, cx| {
 6139                for (_, task) in &resolved_tasks.templates {
 6140                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6141                        task.original_task().clone(),
 6142                        debug_adapter.clone().into(),
 6143                        task.display_label().to_owned().into(),
 6144                        cx,
 6145                    );
 6146                    scenarios.push(maybe_scenario);
 6147                }
 6148            });
 6149            Some(cx.background_spawn(async move {
 6150                let scenarios = futures::future::join_all(scenarios)
 6151                    .await
 6152                    .into_iter()
 6153                    .flatten()
 6154                    .collect::<Vec<_>>();
 6155                scenarios
 6156            }))
 6157        })
 6158        .unwrap_or_else(|| Task::ready(vec![]))
 6159    }
 6160
 6161    fn code_actions(
 6162        &mut self,
 6163        buffer_row: u32,
 6164        window: &mut Window,
 6165        cx: &mut Context<Self>,
 6166    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6167        let mut task = self.code_actions_task.take();
 6168        cx.spawn_in(window, async move |editor, cx| {
 6169            while let Some(prev_task) = task {
 6170                prev_task.await.log_err();
 6171                task = editor
 6172                    .update(cx, |this, _| this.code_actions_task.take())
 6173                    .ok()?;
 6174            }
 6175
 6176            editor
 6177                .update(cx, |editor, cx| {
 6178                    editor
 6179                        .available_code_actions
 6180                        .clone()
 6181                        .and_then(|(location, code_actions)| {
 6182                            let snapshot = location.buffer.read(cx).snapshot();
 6183                            let point_range = location.range.to_point(&snapshot);
 6184                            let point_range = point_range.start.row..=point_range.end.row;
 6185                            if point_range.contains(&buffer_row) {
 6186                                Some(code_actions)
 6187                            } else {
 6188                                None
 6189                            }
 6190                        })
 6191                })
 6192                .ok()
 6193                .flatten()
 6194        })
 6195    }
 6196
 6197    pub fn confirm_code_action(
 6198        &mut self,
 6199        action: &ConfirmCodeAction,
 6200        window: &mut Window,
 6201        cx: &mut Context<Self>,
 6202    ) -> Option<Task<Result<()>>> {
 6203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6204
 6205        let actions_menu =
 6206            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6207                menu
 6208            } else {
 6209                return None;
 6210            };
 6211
 6212        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6213        let action = actions_menu.actions.get(action_ix)?;
 6214        let title = action.label();
 6215        let buffer = actions_menu.buffer;
 6216        let workspace = self.workspace()?;
 6217
 6218        match action {
 6219            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6220                workspace.update(cx, |workspace, cx| {
 6221                    workspace.schedule_resolved_task(
 6222                        task_source_kind,
 6223                        resolved_task,
 6224                        false,
 6225                        window,
 6226                        cx,
 6227                    );
 6228
 6229                    Some(Task::ready(Ok(())))
 6230                })
 6231            }
 6232            CodeActionsItem::CodeAction {
 6233                excerpt_id,
 6234                action,
 6235                provider,
 6236            } => {
 6237                let apply_code_action =
 6238                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6239                let workspace = workspace.downgrade();
 6240                Some(cx.spawn_in(window, async move |editor, cx| {
 6241                    let project_transaction = apply_code_action.await?;
 6242                    Self::open_project_transaction(
 6243                        &editor,
 6244                        workspace,
 6245                        project_transaction,
 6246                        title,
 6247                        cx,
 6248                    )
 6249                    .await
 6250                }))
 6251            }
 6252            CodeActionsItem::DebugScenario(scenario) => {
 6253                let context = actions_menu.actions.context.clone();
 6254
 6255                workspace.update(cx, |workspace, cx| {
 6256                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6257                    workspace.start_debug_session(
 6258                        scenario,
 6259                        context,
 6260                        Some(buffer),
 6261                        None,
 6262                        window,
 6263                        cx,
 6264                    );
 6265                });
 6266                Some(Task::ready(Ok(())))
 6267            }
 6268        }
 6269    }
 6270
 6271    pub async fn open_project_transaction(
 6272        this: &WeakEntity<Editor>,
 6273        workspace: WeakEntity<Workspace>,
 6274        transaction: ProjectTransaction,
 6275        title: String,
 6276        cx: &mut AsyncWindowContext,
 6277    ) -> Result<()> {
 6278        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6279        cx.update(|_, cx| {
 6280            entries.sort_unstable_by_key(|(buffer, _)| {
 6281                buffer.read(cx).file().map(|f| f.path().clone())
 6282            });
 6283        })?;
 6284
 6285        // If the project transaction's edits are all contained within this editor, then
 6286        // avoid opening a new editor to display them.
 6287
 6288        if let Some((buffer, transaction)) = entries.first() {
 6289            if entries.len() == 1 {
 6290                let excerpt = this.update(cx, |editor, cx| {
 6291                    editor
 6292                        .buffer()
 6293                        .read(cx)
 6294                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6295                })?;
 6296                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6297                    if excerpted_buffer == *buffer {
 6298                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6299                            let excerpt_range = excerpt_range.to_offset(buffer);
 6300                            buffer
 6301                                .edited_ranges_for_transaction::<usize>(transaction)
 6302                                .all(|range| {
 6303                                    excerpt_range.start <= range.start
 6304                                        && excerpt_range.end >= range.end
 6305                                })
 6306                        })?;
 6307
 6308                        if all_edits_within_excerpt {
 6309                            return Ok(());
 6310                        }
 6311                    }
 6312                }
 6313            }
 6314        } else {
 6315            return Ok(());
 6316        }
 6317
 6318        let mut ranges_to_highlight = Vec::new();
 6319        let excerpt_buffer = cx.new(|cx| {
 6320            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6321            for (buffer_handle, transaction) in &entries {
 6322                let edited_ranges = buffer_handle
 6323                    .read(cx)
 6324                    .edited_ranges_for_transaction::<Point>(transaction)
 6325                    .collect::<Vec<_>>();
 6326                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6327                    PathKey::for_buffer(buffer_handle, cx),
 6328                    buffer_handle.clone(),
 6329                    edited_ranges,
 6330                    DEFAULT_MULTIBUFFER_CONTEXT,
 6331                    cx,
 6332                );
 6333
 6334                ranges_to_highlight.extend(ranges);
 6335            }
 6336            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6337            multibuffer
 6338        })?;
 6339
 6340        workspace.update_in(cx, |workspace, window, cx| {
 6341            let project = workspace.project().clone();
 6342            let editor =
 6343                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6344            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6345            editor.update(cx, |editor, cx| {
 6346                editor.highlight_background::<Self>(
 6347                    &ranges_to_highlight,
 6348                    |theme| theme.colors().editor_highlighted_line_background,
 6349                    cx,
 6350                );
 6351            });
 6352        })?;
 6353
 6354        Ok(())
 6355    }
 6356
 6357    pub fn clear_code_action_providers(&mut self) {
 6358        self.code_action_providers.clear();
 6359        self.available_code_actions.take();
 6360    }
 6361
 6362    pub fn add_code_action_provider(
 6363        &mut self,
 6364        provider: Rc<dyn CodeActionProvider>,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) {
 6368        if self
 6369            .code_action_providers
 6370            .iter()
 6371            .any(|existing_provider| existing_provider.id() == provider.id())
 6372        {
 6373            return;
 6374        }
 6375
 6376        self.code_action_providers.push(provider);
 6377        self.refresh_code_actions(window, cx);
 6378    }
 6379
 6380    pub fn remove_code_action_provider(
 6381        &mut self,
 6382        id: Arc<str>,
 6383        window: &mut Window,
 6384        cx: &mut Context<Self>,
 6385    ) {
 6386        self.code_action_providers
 6387            .retain(|provider| provider.id() != id);
 6388        self.refresh_code_actions(window, cx);
 6389    }
 6390
 6391    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6392        !self.code_action_providers.is_empty()
 6393            && EditorSettings::get_global(cx).toolbar.code_actions
 6394    }
 6395
 6396    pub fn has_available_code_actions(&self) -> bool {
 6397        self.available_code_actions
 6398            .as_ref()
 6399            .is_some_and(|(_, actions)| !actions.is_empty())
 6400    }
 6401
 6402    fn render_inline_code_actions(
 6403        &self,
 6404        icon_size: ui::IconSize,
 6405        display_row: DisplayRow,
 6406        is_active: bool,
 6407        cx: &mut Context<Self>,
 6408    ) -> AnyElement {
 6409        let show_tooltip = !self.context_menu_visible();
 6410        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6411            .icon_size(icon_size)
 6412            .shape(ui::IconButtonShape::Square)
 6413            .style(ButtonStyle::Transparent)
 6414            .icon_color(ui::Color::Hidden)
 6415            .toggle_state(is_active)
 6416            .when(show_tooltip, |this| {
 6417                this.tooltip({
 6418                    let focus_handle = self.focus_handle.clone();
 6419                    move |window, cx| {
 6420                        Tooltip::for_action_in(
 6421                            "Toggle Code Actions",
 6422                            &ToggleCodeActions {
 6423                                deployed_from: None,
 6424                                quick_launch: false,
 6425                            },
 6426                            &focus_handle,
 6427                            window,
 6428                            cx,
 6429                        )
 6430                    }
 6431                })
 6432            })
 6433            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6434                window.focus(&editor.focus_handle(cx));
 6435                editor.toggle_code_actions(
 6436                    &crate::actions::ToggleCodeActions {
 6437                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6438                            display_row,
 6439                        )),
 6440                        quick_launch: false,
 6441                    },
 6442                    window,
 6443                    cx,
 6444                );
 6445            }))
 6446            .into_any_element()
 6447    }
 6448
 6449    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6450        &self.context_menu
 6451    }
 6452
 6453    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6454        let newest_selection = self.selections.newest_anchor().clone();
 6455        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6456        let buffer = self.buffer.read(cx);
 6457        if newest_selection.head().diff_base_anchor.is_some() {
 6458            return None;
 6459        }
 6460        let (start_buffer, start) =
 6461            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6462        let (end_buffer, end) =
 6463            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6464        if start_buffer != end_buffer {
 6465            return None;
 6466        }
 6467
 6468        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6469            cx.background_executor()
 6470                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6471                .await;
 6472
 6473            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6474                let providers = this.code_action_providers.clone();
 6475                let tasks = this
 6476                    .code_action_providers
 6477                    .iter()
 6478                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6479                    .collect::<Vec<_>>();
 6480                (providers, tasks)
 6481            })?;
 6482
 6483            let mut actions = Vec::new();
 6484            for (provider, provider_actions) in
 6485                providers.into_iter().zip(future::join_all(tasks).await)
 6486            {
 6487                if let Some(provider_actions) = provider_actions.log_err() {
 6488                    actions.extend(provider_actions.into_iter().map(|action| {
 6489                        AvailableCodeAction {
 6490                            excerpt_id: newest_selection.start.excerpt_id,
 6491                            action,
 6492                            provider: provider.clone(),
 6493                        }
 6494                    }));
 6495                }
 6496            }
 6497
 6498            this.update(cx, |this, cx| {
 6499                this.available_code_actions = if actions.is_empty() {
 6500                    None
 6501                } else {
 6502                    Some((
 6503                        Location {
 6504                            buffer: start_buffer,
 6505                            range: start..end,
 6506                        },
 6507                        actions.into(),
 6508                    ))
 6509                };
 6510                cx.notify();
 6511            })
 6512        }));
 6513        None
 6514    }
 6515
 6516    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6517        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6518            self.show_git_blame_inline = false;
 6519
 6520            self.show_git_blame_inline_delay_task =
 6521                Some(cx.spawn_in(window, async move |this, cx| {
 6522                    cx.background_executor().timer(delay).await;
 6523
 6524                    this.update(cx, |this, cx| {
 6525                        this.show_git_blame_inline = true;
 6526                        cx.notify();
 6527                    })
 6528                    .log_err();
 6529                }));
 6530        }
 6531    }
 6532
 6533    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6534        let snapshot = self.snapshot(window, cx);
 6535        let cursor = self.selections.newest::<Point>(cx).head();
 6536        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6537        else {
 6538            return;
 6539        };
 6540
 6541        let Some(blame) = self.blame.as_ref() else {
 6542            return;
 6543        };
 6544
 6545        let row_info = RowInfo {
 6546            buffer_id: Some(buffer.remote_id()),
 6547            buffer_row: Some(point.row),
 6548            ..Default::default()
 6549        };
 6550        let Some(blame_entry) = blame
 6551            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6552            .flatten()
 6553        else {
 6554            return;
 6555        };
 6556
 6557        let anchor = self.selections.newest_anchor().head();
 6558        let position = self.to_pixel_point(anchor, &snapshot, window);
 6559        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6560            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6561        };
 6562    }
 6563
 6564    fn show_blame_popover(
 6565        &mut self,
 6566        blame_entry: &BlameEntry,
 6567        position: gpui::Point<Pixels>,
 6568        ignore_timeout: bool,
 6569        cx: &mut Context<Self>,
 6570    ) {
 6571        if let Some(state) = &mut self.inline_blame_popover {
 6572            state.hide_task.take();
 6573        } else {
 6574            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6575            let blame_entry = blame_entry.clone();
 6576            let show_task = cx.spawn(async move |editor, cx| {
 6577                if !ignore_timeout {
 6578                    cx.background_executor()
 6579                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6580                        .await;
 6581                }
 6582                editor
 6583                    .update(cx, |editor, cx| {
 6584                        editor.inline_blame_popover_show_task.take();
 6585                        let Some(blame) = editor.blame.as_ref() else {
 6586                            return;
 6587                        };
 6588                        let blame = blame.read(cx);
 6589                        let details = blame.details_for_entry(&blame_entry);
 6590                        let markdown = cx.new(|cx| {
 6591                            Markdown::new(
 6592                                details
 6593                                    .as_ref()
 6594                                    .map(|message| message.message.clone())
 6595                                    .unwrap_or_default(),
 6596                                None,
 6597                                None,
 6598                                cx,
 6599                            )
 6600                        });
 6601                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6602                            position,
 6603                            hide_task: None,
 6604                            popover_bounds: None,
 6605                            popover_state: InlineBlamePopoverState {
 6606                                scroll_handle: ScrollHandle::new(),
 6607                                commit_message: details,
 6608                                markdown,
 6609                            },
 6610                            keyboard_grace: ignore_timeout,
 6611                        });
 6612                        cx.notify();
 6613                    })
 6614                    .ok();
 6615            });
 6616            self.inline_blame_popover_show_task = Some(show_task);
 6617        }
 6618    }
 6619
 6620    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6621        self.inline_blame_popover_show_task.take();
 6622        if let Some(state) = &mut self.inline_blame_popover {
 6623            let hide_task = cx.spawn(async move |editor, cx| {
 6624                cx.background_executor()
 6625                    .timer(std::time::Duration::from_millis(100))
 6626                    .await;
 6627                editor
 6628                    .update(cx, |editor, cx| {
 6629                        editor.inline_blame_popover.take();
 6630                        cx.notify();
 6631                    })
 6632                    .ok();
 6633            });
 6634            state.hide_task = Some(hide_task);
 6635        }
 6636    }
 6637
 6638    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6639        if self.pending_rename.is_some() {
 6640            return None;
 6641        }
 6642
 6643        let provider = self.semantics_provider.clone()?;
 6644        let buffer = self.buffer.read(cx);
 6645        let newest_selection = self.selections.newest_anchor().clone();
 6646        let cursor_position = newest_selection.head();
 6647        let (cursor_buffer, cursor_buffer_position) =
 6648            buffer.text_anchor_for_position(cursor_position, cx)?;
 6649        let (tail_buffer, tail_buffer_position) =
 6650            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6651        if cursor_buffer != tail_buffer {
 6652            return None;
 6653        }
 6654
 6655        let snapshot = cursor_buffer.read(cx).snapshot();
 6656        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6657        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6658        if start_word_range != end_word_range {
 6659            self.document_highlights_task.take();
 6660            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6661            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6662            return None;
 6663        }
 6664
 6665        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6666        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6667            cx.background_executor()
 6668                .timer(Duration::from_millis(debounce))
 6669                .await;
 6670
 6671            let highlights = if let Some(highlights) = cx
 6672                .update(|cx| {
 6673                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6674                })
 6675                .ok()
 6676                .flatten()
 6677            {
 6678                highlights.await.log_err()
 6679            } else {
 6680                None
 6681            };
 6682
 6683            if let Some(highlights) = highlights {
 6684                this.update(cx, |this, cx| {
 6685                    if this.pending_rename.is_some() {
 6686                        return;
 6687                    }
 6688
 6689                    let buffer_id = cursor_position.buffer_id;
 6690                    let buffer = this.buffer.read(cx);
 6691                    if !buffer
 6692                        .text_anchor_for_position(cursor_position, cx)
 6693                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6694                    {
 6695                        return;
 6696                    }
 6697
 6698                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6699                    let mut write_ranges = Vec::new();
 6700                    let mut read_ranges = Vec::new();
 6701                    for highlight in highlights {
 6702                        for (excerpt_id, excerpt_range) in
 6703                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6704                        {
 6705                            let start = highlight
 6706                                .range
 6707                                .start
 6708                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6709                            let end = highlight
 6710                                .range
 6711                                .end
 6712                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6713                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6714                                continue;
 6715                            }
 6716
 6717                            let range = Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: start,
 6721                                diff_base_anchor: None,
 6722                            }..Anchor {
 6723                                buffer_id,
 6724                                excerpt_id,
 6725                                text_anchor: end,
 6726                                diff_base_anchor: None,
 6727                            };
 6728                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6729                                write_ranges.push(range);
 6730                            } else {
 6731                                read_ranges.push(range);
 6732                            }
 6733                        }
 6734                    }
 6735
 6736                    this.highlight_background::<DocumentHighlightRead>(
 6737                        &read_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_read_background,
 6739                        cx,
 6740                    );
 6741                    this.highlight_background::<DocumentHighlightWrite>(
 6742                        &write_ranges,
 6743                        |theme| theme.colors().editor_document_highlight_write_background,
 6744                        cx,
 6745                    );
 6746                    cx.notify();
 6747                })
 6748                .log_err();
 6749            }
 6750        }));
 6751        None
 6752    }
 6753
 6754    fn prepare_highlight_query_from_selection(
 6755        &mut self,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Option<(String, Range<Anchor>)> {
 6758        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6759            return None;
 6760        }
 6761        if !EditorSettings::get_global(cx).selection_highlight {
 6762            return None;
 6763        }
 6764        if self.selections.count() != 1 || self.selections.line_mode {
 6765            return None;
 6766        }
 6767        let selection = self.selections.newest::<Point>(cx);
 6768        if selection.is_empty() || selection.start.row != selection.end.row {
 6769            return None;
 6770        }
 6771        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6772        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6773        let query = multi_buffer_snapshot
 6774            .text_for_range(selection_anchor_range.clone())
 6775            .collect::<String>();
 6776        if query.trim().is_empty() {
 6777            return None;
 6778        }
 6779        Some((query, selection_anchor_range))
 6780    }
 6781
 6782    fn update_selection_occurrence_highlights(
 6783        &mut self,
 6784        query_text: String,
 6785        query_range: Range<Anchor>,
 6786        multi_buffer_range_to_query: Range<Point>,
 6787        use_debounce: bool,
 6788        window: &mut Window,
 6789        cx: &mut Context<Editor>,
 6790    ) -> Task<()> {
 6791        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6792        cx.spawn_in(window, async move |editor, cx| {
 6793            if use_debounce {
 6794                cx.background_executor()
 6795                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6796                    .await;
 6797            }
 6798            let match_task = cx.background_spawn(async move {
 6799                let buffer_ranges = multi_buffer_snapshot
 6800                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6801                    .into_iter()
 6802                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6803                let mut match_ranges = Vec::new();
 6804                let Ok(regex) = project::search::SearchQuery::text(
 6805                    query_text.clone(),
 6806                    false,
 6807                    false,
 6808                    false,
 6809                    Default::default(),
 6810                    Default::default(),
 6811                    false,
 6812                    None,
 6813                ) else {
 6814                    return Vec::default();
 6815                };
 6816                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6817                    match_ranges.extend(
 6818                        regex
 6819                            .search(&buffer_snapshot, Some(search_range.clone()))
 6820                            .await
 6821                            .into_iter()
 6822                            .filter_map(|match_range| {
 6823                                let match_start = buffer_snapshot
 6824                                    .anchor_after(search_range.start + match_range.start);
 6825                                let match_end = buffer_snapshot
 6826                                    .anchor_before(search_range.start + match_range.end);
 6827                                let match_anchor_range = Anchor::range_in_buffer(
 6828                                    excerpt_id,
 6829                                    buffer_snapshot.remote_id(),
 6830                                    match_start..match_end,
 6831                                );
 6832                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6833                            }),
 6834                    );
 6835                }
 6836                match_ranges
 6837            });
 6838            let match_ranges = match_task.await;
 6839            editor
 6840                .update_in(cx, |editor, _, cx| {
 6841                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6842                    if !match_ranges.is_empty() {
 6843                        editor.highlight_background::<SelectedTextHighlight>(
 6844                            &match_ranges,
 6845                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6846                            cx,
 6847                        )
 6848                    }
 6849                })
 6850                .log_err();
 6851        })
 6852    }
 6853
 6854    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6855        struct NewlineFold;
 6856        let type_id = std::any::TypeId::of::<NewlineFold>();
 6857        if !self.mode.is_single_line() {
 6858            return;
 6859        }
 6860        let snapshot = self.snapshot(window, cx);
 6861        if snapshot.buffer_snapshot.max_point().row == 0 {
 6862            return;
 6863        }
 6864        let task = cx.background_spawn(async move {
 6865            let new_newlines = snapshot
 6866                .buffer_chars_at(0)
 6867                .filter_map(|(c, i)| {
 6868                    if c == '\n' {
 6869                        Some(
 6870                            snapshot.buffer_snapshot.anchor_after(i)
 6871                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6872                        )
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878            let existing_newlines = snapshot
 6879                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6880                .filter_map(|fold| {
 6881                    if fold.placeholder.type_tag == Some(type_id) {
 6882                        Some(fold.range.start..fold.range.end)
 6883                    } else {
 6884                        None
 6885                    }
 6886                })
 6887                .collect::<Vec<_>>();
 6888
 6889            (new_newlines, existing_newlines)
 6890        });
 6891        self.folding_newlines = cx.spawn(async move |this, cx| {
 6892            let (new_newlines, existing_newlines) = task.await;
 6893            if new_newlines == existing_newlines {
 6894                return;
 6895            }
 6896            let placeholder = FoldPlaceholder {
 6897                render: Arc::new(move |_, _, cx| {
 6898                    div()
 6899                        .bg(cx.theme().status().hint_background)
 6900                        .border_b_1()
 6901                        .size_full()
 6902                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6903                        .border_color(cx.theme().status().hint)
 6904                        .child("\\n")
 6905                        .into_any()
 6906                }),
 6907                constrain_width: false,
 6908                merge_adjacent: false,
 6909                type_tag: Some(type_id),
 6910            };
 6911            let creases = new_newlines
 6912                .into_iter()
 6913                .map(|range| Crease::simple(range, placeholder.clone()))
 6914                .collect();
 6915            this.update(cx, |this, cx| {
 6916                this.display_map.update(cx, |display_map, cx| {
 6917                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6918                    display_map.fold(creases, cx);
 6919                });
 6920            })
 6921            .ok();
 6922        });
 6923    }
 6924
 6925    fn refresh_selected_text_highlights(
 6926        &mut self,
 6927        on_buffer_edit: bool,
 6928        window: &mut Window,
 6929        cx: &mut Context<Editor>,
 6930    ) {
 6931        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6932        else {
 6933            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6934            self.quick_selection_highlight_task.take();
 6935            self.debounced_selection_highlight_task.take();
 6936            return;
 6937        };
 6938        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6939        if on_buffer_edit
 6940            || self
 6941                .quick_selection_highlight_task
 6942                .as_ref()
 6943                .map_or(true, |(prev_anchor_range, _)| {
 6944                    prev_anchor_range != &query_range
 6945                })
 6946        {
 6947            let multi_buffer_visible_start = self
 6948                .scroll_manager
 6949                .anchor()
 6950                .anchor
 6951                .to_point(&multi_buffer_snapshot);
 6952            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6953                multi_buffer_visible_start
 6954                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6955                Bias::Left,
 6956            );
 6957            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6958            self.quick_selection_highlight_task = Some((
 6959                query_range.clone(),
 6960                self.update_selection_occurrence_highlights(
 6961                    query_text.clone(),
 6962                    query_range.clone(),
 6963                    multi_buffer_visible_range,
 6964                    false,
 6965                    window,
 6966                    cx,
 6967                ),
 6968            ));
 6969        }
 6970        if on_buffer_edit
 6971            || self
 6972                .debounced_selection_highlight_task
 6973                .as_ref()
 6974                .map_or(true, |(prev_anchor_range, _)| {
 6975                    prev_anchor_range != &query_range
 6976                })
 6977        {
 6978            let multi_buffer_start = multi_buffer_snapshot
 6979                .anchor_before(0)
 6980                .to_point(&multi_buffer_snapshot);
 6981            let multi_buffer_end = multi_buffer_snapshot
 6982                .anchor_after(multi_buffer_snapshot.len())
 6983                .to_point(&multi_buffer_snapshot);
 6984            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6985            self.debounced_selection_highlight_task = Some((
 6986                query_range.clone(),
 6987                self.update_selection_occurrence_highlights(
 6988                    query_text,
 6989                    query_range,
 6990                    multi_buffer_full_range,
 6991                    true,
 6992                    window,
 6993                    cx,
 6994                ),
 6995            ));
 6996        }
 6997    }
 6998
 6999    pub fn refresh_inline_completion(
 7000        &mut self,
 7001        debounce: bool,
 7002        user_requested: bool,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) -> Option<()> {
 7006        let provider = self.edit_prediction_provider()?;
 7007        let cursor = self.selections.newest_anchor().head();
 7008        let (buffer, cursor_buffer_position) =
 7009            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7010
 7011        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7012            self.discard_inline_completion(false, cx);
 7013            return None;
 7014        }
 7015
 7016        if !user_requested
 7017            && (!self.should_show_edit_predictions()
 7018                || !self.is_focused(window)
 7019                || buffer.read(cx).is_empty())
 7020        {
 7021            self.discard_inline_completion(false, cx);
 7022            return None;
 7023        }
 7024
 7025        self.update_visible_inline_completion(window, cx);
 7026        provider.refresh(
 7027            self.project.clone(),
 7028            buffer,
 7029            cursor_buffer_position,
 7030            debounce,
 7031            cx,
 7032        );
 7033        Some(())
 7034    }
 7035
 7036    fn show_edit_predictions_in_menu(&self) -> bool {
 7037        match self.edit_prediction_settings {
 7038            EditPredictionSettings::Disabled => false,
 7039            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7040        }
 7041    }
 7042
 7043    pub fn edit_predictions_enabled(&self) -> bool {
 7044        match self.edit_prediction_settings {
 7045            EditPredictionSettings::Disabled => false,
 7046            EditPredictionSettings::Enabled { .. } => true,
 7047        }
 7048    }
 7049
 7050    fn edit_prediction_requires_modifier(&self) -> bool {
 7051        match self.edit_prediction_settings {
 7052            EditPredictionSettings::Disabled => false,
 7053            EditPredictionSettings::Enabled {
 7054                preview_requires_modifier,
 7055                ..
 7056            } => preview_requires_modifier,
 7057        }
 7058    }
 7059
 7060    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7061        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7062            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7063        } else {
 7064            let selection = self.selections.newest_anchor();
 7065            let cursor = selection.head();
 7066
 7067            if let Some((buffer, cursor_buffer_position)) =
 7068                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7069            {
 7070                self.edit_prediction_settings =
 7071                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7072            }
 7073        }
 7074    }
 7075
 7076    fn edit_prediction_settings_at_position(
 7077        &self,
 7078        buffer: &Entity<Buffer>,
 7079        buffer_position: language::Anchor,
 7080        cx: &App,
 7081    ) -> EditPredictionSettings {
 7082        if !self.mode.is_full()
 7083            || !self.show_inline_completions_override.unwrap_or(true)
 7084            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7085        {
 7086            return EditPredictionSettings::Disabled;
 7087        }
 7088
 7089        let buffer = buffer.read(cx);
 7090
 7091        let file = buffer.file();
 7092
 7093        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7094            return EditPredictionSettings::Disabled;
 7095        };
 7096
 7097        let by_provider = matches!(
 7098            self.menu_inline_completions_policy,
 7099            MenuInlineCompletionsPolicy::ByProvider
 7100        );
 7101
 7102        let show_in_menu = by_provider
 7103            && self
 7104                .edit_prediction_provider
 7105                .as_ref()
 7106                .map_or(false, |provider| {
 7107                    provider.provider.show_completions_in_menu()
 7108                });
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_inline_completion(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_inline_completion(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_inline_completion(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_inline_completion() {
 7196            self.refresh_inline_completion(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_inline_completion(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_inline_completion() {
 7233            self.cycle_inline_completion(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_inline_completion(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_inline_completion() {
 7251            self.cycle_inline_completion(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_inline_completion(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        self.report_inline_completion_event(
 7277            active_inline_completion.completion_id.clone(),
 7278            true,
 7279            cx,
 7280        );
 7281
 7282        match &active_inline_completion.completion {
 7283            InlineCompletion::Move { target, .. } => {
 7284                let target = *target;
 7285
 7286                if let Some(position_map) = &self.last_position_map {
 7287                    if position_map
 7288                        .visible_row_range
 7289                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7290                        || !self.edit_prediction_requires_modifier()
 7291                    {
 7292                        self.unfold_ranges(&[target..target], true, false, cx);
 7293                        // Note that this is also done in vim's handler of the Tab action.
 7294                        self.change_selections(
 7295                            SelectionEffects::scroll(Autoscroll::newest()),
 7296                            window,
 7297                            cx,
 7298                            |selections| {
 7299                                selections.select_anchor_ranges([target..target]);
 7300                            },
 7301                        );
 7302                        self.clear_row_highlights::<EditPredictionPreview>();
 7303
 7304                        self.edit_prediction_preview
 7305                            .set_previous_scroll_position(None);
 7306                    } else {
 7307                        self.edit_prediction_preview
 7308                            .set_previous_scroll_position(Some(
 7309                                position_map.snapshot.scroll_anchor,
 7310                            ));
 7311
 7312                        self.highlight_rows::<EditPredictionPreview>(
 7313                            target..target,
 7314                            cx.theme().colors().editor_highlighted_line_background,
 7315                            RowHighlightOptions {
 7316                                autoscroll: true,
 7317                                ..Default::default()
 7318                            },
 7319                            cx,
 7320                        );
 7321                        self.request_autoscroll(Autoscroll::fit(), cx);
 7322                    }
 7323                }
 7324            }
 7325            InlineCompletion::Edit { edits, .. } => {
 7326                if let Some(provider) = self.edit_prediction_provider() {
 7327                    provider.accept(cx);
 7328                }
 7329
 7330                // Store the transaction ID and selections before applying the edit
 7331                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7332
 7333                let snapshot = self.buffer.read(cx).snapshot(cx);
 7334                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7335
 7336                self.buffer.update(cx, |buffer, cx| {
 7337                    buffer.edit(edits.iter().cloned(), None, cx)
 7338                });
 7339
 7340                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7341                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7342                });
 7343
 7344                let selections = self.selections.disjoint_anchors();
 7345                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7346                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7347                    if has_new_transaction {
 7348                        self.selection_history
 7349                            .insert_transaction(transaction_id_now, selections);
 7350                    }
 7351                }
 7352
 7353                self.update_visible_inline_completion(window, cx);
 7354                if self.active_inline_completion.is_none() {
 7355                    self.refresh_inline_completion(true, true, window, cx);
 7356                }
 7357
 7358                cx.notify();
 7359            }
 7360        }
 7361
 7362        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7363    }
 7364
 7365    pub fn accept_partial_inline_completion(
 7366        &mut self,
 7367        _: &AcceptPartialEditPrediction,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) {
 7371        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7372            return;
 7373        };
 7374        if self.selections.count() != 1 {
 7375            return;
 7376        }
 7377
 7378        self.report_inline_completion_event(
 7379            active_inline_completion.completion_id.clone(),
 7380            true,
 7381            cx,
 7382        );
 7383
 7384        match &active_inline_completion.completion {
 7385            InlineCompletion::Move { target, .. } => {
 7386                let target = *target;
 7387                self.change_selections(
 7388                    SelectionEffects::scroll(Autoscroll::newest()),
 7389                    window,
 7390                    cx,
 7391                    |selections| {
 7392                        selections.select_anchor_ranges([target..target]);
 7393                    },
 7394                );
 7395            }
 7396            InlineCompletion::Edit { edits, .. } => {
 7397                // Find an insertion that starts at the cursor position.
 7398                let snapshot = self.buffer.read(cx).snapshot(cx);
 7399                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7400                let insertion = edits.iter().find_map(|(range, text)| {
 7401                    let range = range.to_offset(&snapshot);
 7402                    if range.is_empty() && range.start == cursor_offset {
 7403                        Some(text)
 7404                    } else {
 7405                        None
 7406                    }
 7407                });
 7408
 7409                if let Some(text) = insertion {
 7410                    let mut partial_completion = text
 7411                        .chars()
 7412                        .by_ref()
 7413                        .take_while(|c| c.is_alphabetic())
 7414                        .collect::<String>();
 7415                    if partial_completion.is_empty() {
 7416                        partial_completion = text
 7417                            .chars()
 7418                            .by_ref()
 7419                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7420                            .collect::<String>();
 7421                    }
 7422
 7423                    cx.emit(EditorEvent::InputHandled {
 7424                        utf16_range_to_replace: None,
 7425                        text: partial_completion.clone().into(),
 7426                    });
 7427
 7428                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7429
 7430                    self.refresh_inline_completion(true, true, window, cx);
 7431                    cx.notify();
 7432                } else {
 7433                    self.accept_edit_prediction(&Default::default(), window, cx);
 7434                }
 7435            }
 7436        }
 7437    }
 7438
 7439    fn discard_inline_completion(
 7440        &mut self,
 7441        should_report_inline_completion_event: bool,
 7442        cx: &mut Context<Self>,
 7443    ) -> bool {
 7444        if should_report_inline_completion_event {
 7445            let completion_id = self
 7446                .active_inline_completion
 7447                .as_ref()
 7448                .and_then(|active_completion| active_completion.completion_id.clone());
 7449
 7450            self.report_inline_completion_event(completion_id, false, cx);
 7451        }
 7452
 7453        if let Some(provider) = self.edit_prediction_provider() {
 7454            provider.discard(cx);
 7455        }
 7456
 7457        self.take_active_inline_completion(cx)
 7458    }
 7459
 7460    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7461        let Some(provider) = self.edit_prediction_provider() else {
 7462            return;
 7463        };
 7464
 7465        let Some((_, buffer, _)) = self
 7466            .buffer
 7467            .read(cx)
 7468            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7469        else {
 7470            return;
 7471        };
 7472
 7473        let extension = buffer
 7474            .read(cx)
 7475            .file()
 7476            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7477
 7478        let event_type = match accepted {
 7479            true => "Edit Prediction Accepted",
 7480            false => "Edit Prediction Discarded",
 7481        };
 7482        telemetry::event!(
 7483            event_type,
 7484            provider = provider.name(),
 7485            prediction_id = id,
 7486            suggestion_accepted = accepted,
 7487            file_extension = extension,
 7488        );
 7489    }
 7490
 7491    pub fn has_active_inline_completion(&self) -> bool {
 7492        self.active_inline_completion.is_some()
 7493    }
 7494
 7495    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7496        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7497            return false;
 7498        };
 7499
 7500        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7501        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7502        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7503        true
 7504    }
 7505
 7506    /// Returns true when we're displaying the edit prediction popover below the cursor
 7507    /// like we are not previewing and the LSP autocomplete menu is visible
 7508    /// or we are in `when_holding_modifier` mode.
 7509    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7510        if self.edit_prediction_preview_is_active()
 7511            || !self.show_edit_predictions_in_menu()
 7512            || !self.edit_predictions_enabled()
 7513        {
 7514            return false;
 7515        }
 7516
 7517        if self.has_visible_completions_menu() {
 7518            return true;
 7519        }
 7520
 7521        has_completion && self.edit_prediction_requires_modifier()
 7522    }
 7523
 7524    fn handle_modifiers_changed(
 7525        &mut self,
 7526        modifiers: Modifiers,
 7527        position_map: &PositionMap,
 7528        window: &mut Window,
 7529        cx: &mut Context<Self>,
 7530    ) {
 7531        if self.show_edit_predictions_in_menu() {
 7532            self.update_edit_prediction_preview(&modifiers, window, cx);
 7533        }
 7534
 7535        self.update_selection_mode(&modifiers, position_map, window, cx);
 7536
 7537        let mouse_position = window.mouse_position();
 7538        if !position_map.text_hitbox.is_hovered(window) {
 7539            return;
 7540        }
 7541
 7542        self.update_hovered_link(
 7543            position_map.point_for_position(mouse_position),
 7544            &position_map.snapshot,
 7545            modifiers,
 7546            window,
 7547            cx,
 7548        )
 7549    }
 7550
 7551    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7552        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7553        if invert {
 7554            match multi_cursor_setting {
 7555                MultiCursorModifier::Alt => modifiers.alt,
 7556                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7557            }
 7558        } else {
 7559            match multi_cursor_setting {
 7560                MultiCursorModifier::Alt => modifiers.secondary(),
 7561                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7562            }
 7563        }
 7564    }
 7565
 7566    fn columnar_selection_mode(
 7567        modifiers: &Modifiers,
 7568        cx: &mut Context<Self>,
 7569    ) -> Option<ColumnarMode> {
 7570        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7571            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7572                Some(ColumnarMode::FromMouse)
 7573            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7574                Some(ColumnarMode::FromSelection)
 7575            } else {
 7576                None
 7577            }
 7578        } else {
 7579            None
 7580        }
 7581    }
 7582
 7583    fn update_selection_mode(
 7584        &mut self,
 7585        modifiers: &Modifiers,
 7586        position_map: &PositionMap,
 7587        window: &mut Window,
 7588        cx: &mut Context<Self>,
 7589    ) {
 7590        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7591            return;
 7592        };
 7593        if self.selections.pending.is_none() {
 7594            return;
 7595        }
 7596
 7597        let mouse_position = window.mouse_position();
 7598        let point_for_position = position_map.point_for_position(mouse_position);
 7599        let position = point_for_position.previous_valid;
 7600
 7601        self.select(
 7602            SelectPhase::BeginColumnar {
 7603                position,
 7604                reset: false,
 7605                mode,
 7606                goal_column: point_for_position.exact_unclipped.column(),
 7607            },
 7608            window,
 7609            cx,
 7610        );
 7611    }
 7612
 7613    fn update_edit_prediction_preview(
 7614        &mut self,
 7615        modifiers: &Modifiers,
 7616        window: &mut Window,
 7617        cx: &mut Context<Self>,
 7618    ) {
 7619        let mut modifiers_held = false;
 7620        if let Some(accept_keystroke) = self
 7621            .accept_edit_prediction_keybind(false, window, cx)
 7622            .keystroke()
 7623        {
 7624            modifiers_held = modifiers_held
 7625                || (&accept_keystroke.modifiers == modifiers
 7626                    && accept_keystroke.modifiers.modified());
 7627        };
 7628        if let Some(accept_partial_keystroke) = self
 7629            .accept_edit_prediction_keybind(true, window, cx)
 7630            .keystroke()
 7631        {
 7632            modifiers_held = modifiers_held
 7633                || (&accept_partial_keystroke.modifiers == modifiers
 7634                    && accept_partial_keystroke.modifiers.modified());
 7635        }
 7636
 7637        if modifiers_held {
 7638            if matches!(
 7639                self.edit_prediction_preview,
 7640                EditPredictionPreview::Inactive { .. }
 7641            ) {
 7642                self.edit_prediction_preview = EditPredictionPreview::Active {
 7643                    previous_scroll_position: None,
 7644                    since: Instant::now(),
 7645                };
 7646
 7647                self.update_visible_inline_completion(window, cx);
 7648                cx.notify();
 7649            }
 7650        } else if let EditPredictionPreview::Active {
 7651            previous_scroll_position,
 7652            since,
 7653        } = self.edit_prediction_preview
 7654        {
 7655            if let (Some(previous_scroll_position), Some(position_map)) =
 7656                (previous_scroll_position, self.last_position_map.as_ref())
 7657            {
 7658                self.set_scroll_position(
 7659                    previous_scroll_position
 7660                        .scroll_position(&position_map.snapshot.display_snapshot),
 7661                    window,
 7662                    cx,
 7663                );
 7664            }
 7665
 7666            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7667                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7668            };
 7669            self.clear_row_highlights::<EditPredictionPreview>();
 7670            self.update_visible_inline_completion(window, cx);
 7671            cx.notify();
 7672        }
 7673    }
 7674
 7675    fn update_visible_inline_completion(
 7676        &mut self,
 7677        _window: &mut Window,
 7678        cx: &mut Context<Self>,
 7679    ) -> Option<()> {
 7680        let selection = self.selections.newest_anchor();
 7681        let cursor = selection.head();
 7682        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7683        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7684        let excerpt_id = cursor.excerpt_id;
 7685
 7686        let show_in_menu = self.show_edit_predictions_in_menu();
 7687        let completions_menu_has_precedence = !show_in_menu
 7688            && (self.context_menu.borrow().is_some()
 7689                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7690
 7691        if completions_menu_has_precedence
 7692            || !offset_selection.is_empty()
 7693            || self
 7694                .active_inline_completion
 7695                .as_ref()
 7696                .map_or(false, |completion| {
 7697                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7698                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7699                    !invalidation_range.contains(&offset_selection.head())
 7700                })
 7701        {
 7702            self.discard_inline_completion(false, cx);
 7703            return None;
 7704        }
 7705
 7706        self.take_active_inline_completion(cx);
 7707        let Some(provider) = self.edit_prediction_provider() else {
 7708            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7709            return None;
 7710        };
 7711
 7712        let (buffer, cursor_buffer_position) =
 7713            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7714
 7715        self.edit_prediction_settings =
 7716            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7717
 7718        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7719
 7720        if self.edit_prediction_indent_conflict {
 7721            let cursor_point = cursor.to_point(&multibuffer);
 7722
 7723            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7724
 7725            if let Some((_, indent)) = indents.iter().next() {
 7726                if indent.len == cursor_point.column {
 7727                    self.edit_prediction_indent_conflict = false;
 7728                }
 7729            }
 7730        }
 7731
 7732        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7733        let edits = inline_completion
 7734            .edits
 7735            .into_iter()
 7736            .flat_map(|(range, new_text)| {
 7737                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7738                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7739                Some((start..end, new_text))
 7740            })
 7741            .collect::<Vec<_>>();
 7742        if edits.is_empty() {
 7743            return None;
 7744        }
 7745
 7746        let first_edit_start = edits.first().unwrap().0.start;
 7747        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7748        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7749
 7750        let last_edit_end = edits.last().unwrap().0.end;
 7751        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7752        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7753
 7754        let cursor_row = cursor.to_point(&multibuffer).row;
 7755
 7756        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7757
 7758        let mut inlay_ids = Vec::new();
 7759        let invalidation_row_range;
 7760        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7761            Some(cursor_row..edit_end_row)
 7762        } else if cursor_row > edit_end_row {
 7763            Some(edit_start_row..cursor_row)
 7764        } else {
 7765            None
 7766        };
 7767        let is_move =
 7768            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7769        let completion = if is_move {
 7770            invalidation_row_range =
 7771                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7772            let target = first_edit_start;
 7773            InlineCompletion::Move { target, snapshot }
 7774        } else {
 7775            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7776                && !self.inline_completions_hidden_for_vim_mode;
 7777
 7778            if show_completions_in_buffer {
 7779                if edits
 7780                    .iter()
 7781                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7782                {
 7783                    let mut inlays = Vec::new();
 7784                    for (range, new_text) in &edits {
 7785                        let inlay = Inlay::inline_completion(
 7786                            post_inc(&mut self.next_inlay_id),
 7787                            range.start,
 7788                            new_text.as_str(),
 7789                        );
 7790                        inlay_ids.push(inlay.id);
 7791                        inlays.push(inlay);
 7792                    }
 7793
 7794                    self.splice_inlays(&[], inlays, cx);
 7795                } else {
 7796                    let background_color = cx.theme().status().deleted_background;
 7797                    self.highlight_text::<InlineCompletionHighlight>(
 7798                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7799                        HighlightStyle {
 7800                            background_color: Some(background_color),
 7801                            ..Default::default()
 7802                        },
 7803                        cx,
 7804                    );
 7805                }
 7806            }
 7807
 7808            invalidation_row_range = edit_start_row..edit_end_row;
 7809
 7810            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7811                if provider.show_tab_accept_marker() {
 7812                    EditDisplayMode::TabAccept
 7813                } else {
 7814                    EditDisplayMode::Inline
 7815                }
 7816            } else {
 7817                EditDisplayMode::DiffPopover
 7818            };
 7819
 7820            InlineCompletion::Edit {
 7821                edits,
 7822                edit_preview: inline_completion.edit_preview,
 7823                display_mode,
 7824                snapshot,
 7825            }
 7826        };
 7827
 7828        let invalidation_range = multibuffer
 7829            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7830            ..multibuffer.anchor_after(Point::new(
 7831                invalidation_row_range.end,
 7832                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7833            ));
 7834
 7835        self.stale_inline_completion_in_menu = None;
 7836        self.active_inline_completion = Some(InlineCompletionState {
 7837            inlay_ids,
 7838            completion,
 7839            completion_id: inline_completion.id,
 7840            invalidation_range,
 7841        });
 7842
 7843        cx.notify();
 7844
 7845        Some(())
 7846    }
 7847
 7848    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7849        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7850    }
 7851
 7852    fn clear_tasks(&mut self) {
 7853        self.tasks.clear()
 7854    }
 7855
 7856    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7857        if self.tasks.insert(key, value).is_some() {
 7858            // This case should hopefully be rare, but just in case...
 7859            log::error!(
 7860                "multiple different run targets found on a single line, only the last target will be rendered"
 7861            )
 7862        }
 7863    }
 7864
 7865    /// Get all display points of breakpoints that will be rendered within editor
 7866    ///
 7867    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7868    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7869    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7870    fn active_breakpoints(
 7871        &self,
 7872        range: Range<DisplayRow>,
 7873        window: &mut Window,
 7874        cx: &mut Context<Self>,
 7875    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7876        let mut breakpoint_display_points = HashMap::default();
 7877
 7878        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7879            return breakpoint_display_points;
 7880        };
 7881
 7882        let snapshot = self.snapshot(window, cx);
 7883
 7884        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7885        let Some(project) = self.project.as_ref() else {
 7886            return breakpoint_display_points;
 7887        };
 7888
 7889        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7890            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7891
 7892        for (buffer_snapshot, range, excerpt_id) in
 7893            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7894        {
 7895            let Some(buffer) = project
 7896                .read(cx)
 7897                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7898            else {
 7899                continue;
 7900            };
 7901            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7902                &buffer,
 7903                Some(
 7904                    buffer_snapshot.anchor_before(range.start)
 7905                        ..buffer_snapshot.anchor_after(range.end),
 7906                ),
 7907                buffer_snapshot,
 7908                cx,
 7909            );
 7910            for (breakpoint, state) in breakpoints {
 7911                let multi_buffer_anchor =
 7912                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7913                let position = multi_buffer_anchor
 7914                    .to_point(&multi_buffer_snapshot)
 7915                    .to_display_point(&snapshot);
 7916
 7917                breakpoint_display_points.insert(
 7918                    position.row(),
 7919                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7920                );
 7921            }
 7922        }
 7923
 7924        breakpoint_display_points
 7925    }
 7926
 7927    fn breakpoint_context_menu(
 7928        &self,
 7929        anchor: Anchor,
 7930        window: &mut Window,
 7931        cx: &mut Context<Self>,
 7932    ) -> Entity<ui::ContextMenu> {
 7933        let weak_editor = cx.weak_entity();
 7934        let focus_handle = self.focus_handle(cx);
 7935
 7936        let row = self
 7937            .buffer
 7938            .read(cx)
 7939            .snapshot(cx)
 7940            .summary_for_anchor::<Point>(&anchor)
 7941            .row;
 7942
 7943        let breakpoint = self
 7944            .breakpoint_at_row(row, window, cx)
 7945            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7946
 7947        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7948            "Edit Log Breakpoint"
 7949        } else {
 7950            "Set Log Breakpoint"
 7951        };
 7952
 7953        let condition_breakpoint_msg = if breakpoint
 7954            .as_ref()
 7955            .is_some_and(|bp| bp.1.condition.is_some())
 7956        {
 7957            "Edit Condition Breakpoint"
 7958        } else {
 7959            "Set Condition Breakpoint"
 7960        };
 7961
 7962        let hit_condition_breakpoint_msg = if breakpoint
 7963            .as_ref()
 7964            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7965        {
 7966            "Edit Hit Condition Breakpoint"
 7967        } else {
 7968            "Set Hit Condition Breakpoint"
 7969        };
 7970
 7971        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7972            "Unset Breakpoint"
 7973        } else {
 7974            "Set Breakpoint"
 7975        };
 7976
 7977        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7978
 7979        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7980            BreakpointState::Enabled => Some("Disable"),
 7981            BreakpointState::Disabled => Some("Enable"),
 7982        });
 7983
 7984        let (anchor, breakpoint) =
 7985            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7986
 7987        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7988            menu.on_blur_subscription(Subscription::new(|| {}))
 7989                .context(focus_handle)
 7990                .when(run_to_cursor, |this| {
 7991                    let weak_editor = weak_editor.clone();
 7992                    this.entry("Run to cursor", None, move |window, cx| {
 7993                        weak_editor
 7994                            .update(cx, |editor, cx| {
 7995                                editor.change_selections(
 7996                                    SelectionEffects::no_scroll(),
 7997                                    window,
 7998                                    cx,
 7999                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8000                                );
 8001                            })
 8002                            .ok();
 8003
 8004                        window.dispatch_action(Box::new(RunToCursor), cx);
 8005                    })
 8006                    .separator()
 8007                })
 8008                .when_some(toggle_state_msg, |this, msg| {
 8009                    this.entry(msg, None, {
 8010                        let weak_editor = weak_editor.clone();
 8011                        let breakpoint = breakpoint.clone();
 8012                        move |_window, cx| {
 8013                            weak_editor
 8014                                .update(cx, |this, cx| {
 8015                                    this.edit_breakpoint_at_anchor(
 8016                                        anchor,
 8017                                        breakpoint.as_ref().clone(),
 8018                                        BreakpointEditAction::InvertState,
 8019                                        cx,
 8020                                    );
 8021                                })
 8022                                .log_err();
 8023                        }
 8024                    })
 8025                })
 8026                .entry(set_breakpoint_msg, None, {
 8027                    let weak_editor = weak_editor.clone();
 8028                    let breakpoint = breakpoint.clone();
 8029                    move |_window, cx| {
 8030                        weak_editor
 8031                            .update(cx, |this, cx| {
 8032                                this.edit_breakpoint_at_anchor(
 8033                                    anchor,
 8034                                    breakpoint.as_ref().clone(),
 8035                                    BreakpointEditAction::Toggle,
 8036                                    cx,
 8037                                );
 8038                            })
 8039                            .log_err();
 8040                    }
 8041                })
 8042                .entry(log_breakpoint_msg, None, {
 8043                    let breakpoint = breakpoint.clone();
 8044                    let weak_editor = weak_editor.clone();
 8045                    move |window, cx| {
 8046                        weak_editor
 8047                            .update(cx, |this, cx| {
 8048                                this.add_edit_breakpoint_block(
 8049                                    anchor,
 8050                                    breakpoint.as_ref(),
 8051                                    BreakpointPromptEditAction::Log,
 8052                                    window,
 8053                                    cx,
 8054                                );
 8055                            })
 8056                            .log_err();
 8057                    }
 8058                })
 8059                .entry(condition_breakpoint_msg, None, {
 8060                    let breakpoint = breakpoint.clone();
 8061                    let weak_editor = weak_editor.clone();
 8062                    move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |this, cx| {
 8065                                this.add_edit_breakpoint_block(
 8066                                    anchor,
 8067                                    breakpoint.as_ref(),
 8068                                    BreakpointPromptEditAction::Condition,
 8069                                    window,
 8070                                    cx,
 8071                                );
 8072                            })
 8073                            .log_err();
 8074                    }
 8075                })
 8076                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8077                    weak_editor
 8078                        .update(cx, |this, cx| {
 8079                            this.add_edit_breakpoint_block(
 8080                                anchor,
 8081                                breakpoint.as_ref(),
 8082                                BreakpointPromptEditAction::HitCondition,
 8083                                window,
 8084                                cx,
 8085                            );
 8086                        })
 8087                        .log_err();
 8088                })
 8089        })
 8090    }
 8091
 8092    fn render_breakpoint(
 8093        &self,
 8094        position: Anchor,
 8095        row: DisplayRow,
 8096        breakpoint: &Breakpoint,
 8097        state: Option<BreakpointSessionState>,
 8098        cx: &mut Context<Self>,
 8099    ) -> IconButton {
 8100        let is_rejected = state.is_some_and(|s| !s.verified);
 8101        // Is it a breakpoint that shows up when hovering over gutter?
 8102        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8103            (false, false),
 8104            |PhantomBreakpointIndicator {
 8105                 is_active,
 8106                 display_row,
 8107                 collides_with_existing_breakpoint,
 8108             }| {
 8109                (
 8110                    is_active && display_row == row,
 8111                    collides_with_existing_breakpoint,
 8112                )
 8113            },
 8114        );
 8115
 8116        let (color, icon) = {
 8117            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8118                (false, false) => ui::IconName::DebugBreakpoint,
 8119                (true, false) => ui::IconName::DebugLogBreakpoint,
 8120                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8121                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8122            };
 8123
 8124            let color = if is_phantom {
 8125                Color::Hint
 8126            } else if is_rejected {
 8127                Color::Disabled
 8128            } else {
 8129                Color::Debugger
 8130            };
 8131
 8132            (color, icon)
 8133        };
 8134
 8135        let breakpoint = Arc::from(breakpoint.clone());
 8136
 8137        let alt_as_text = gpui::Keystroke {
 8138            modifiers: Modifiers::secondary_key(),
 8139            ..Default::default()
 8140        };
 8141        let primary_action_text = if breakpoint.is_disabled() {
 8142            "Enable breakpoint"
 8143        } else if is_phantom && !collides_with_existing {
 8144            "Set breakpoint"
 8145        } else {
 8146            "Unset breakpoint"
 8147        };
 8148        let focus_handle = self.focus_handle.clone();
 8149
 8150        let meta = if is_rejected {
 8151            SharedString::from("No executable code is associated with this line.")
 8152        } else if collides_with_existing && !breakpoint.is_disabled() {
 8153            SharedString::from(format!(
 8154                "{alt_as_text}-click to disable,\nright-click for more options."
 8155            ))
 8156        } else {
 8157            SharedString::from("Right-click for more options.")
 8158        };
 8159        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8160            .icon_size(IconSize::XSmall)
 8161            .size(ui::ButtonSize::None)
 8162            .when(is_rejected, |this| {
 8163                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8164            })
 8165            .icon_color(color)
 8166            .style(ButtonStyle::Transparent)
 8167            .on_click(cx.listener({
 8168                let breakpoint = breakpoint.clone();
 8169
 8170                move |editor, event: &ClickEvent, window, cx| {
 8171                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8172                        BreakpointEditAction::InvertState
 8173                    } else {
 8174                        BreakpointEditAction::Toggle
 8175                    };
 8176
 8177                    window.focus(&editor.focus_handle(cx));
 8178                    editor.edit_breakpoint_at_anchor(
 8179                        position,
 8180                        breakpoint.as_ref().clone(),
 8181                        edit_action,
 8182                        cx,
 8183                    );
 8184                }
 8185            }))
 8186            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8187                editor.set_breakpoint_context_menu(
 8188                    row,
 8189                    Some(position),
 8190                    event.down.position,
 8191                    window,
 8192                    cx,
 8193                );
 8194            }))
 8195            .tooltip(move |window, cx| {
 8196                Tooltip::with_meta_in(
 8197                    primary_action_text,
 8198                    Some(&ToggleBreakpoint),
 8199                    meta.clone(),
 8200                    &focus_handle,
 8201                    window,
 8202                    cx,
 8203                )
 8204            })
 8205    }
 8206
 8207    fn build_tasks_context(
 8208        project: &Entity<Project>,
 8209        buffer: &Entity<Buffer>,
 8210        buffer_row: u32,
 8211        tasks: &Arc<RunnableTasks>,
 8212        cx: &mut Context<Self>,
 8213    ) -> Task<Option<task::TaskContext>> {
 8214        let position = Point::new(buffer_row, tasks.column);
 8215        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8216        let location = Location {
 8217            buffer: buffer.clone(),
 8218            range: range_start..range_start,
 8219        };
 8220        // Fill in the environmental variables from the tree-sitter captures
 8221        let mut captured_task_variables = TaskVariables::default();
 8222        for (capture_name, value) in tasks.extra_variables.clone() {
 8223            captured_task_variables.insert(
 8224                task::VariableName::Custom(capture_name.into()),
 8225                value.clone(),
 8226            );
 8227        }
 8228        project.update(cx, |project, cx| {
 8229            project.task_store().update(cx, |task_store, cx| {
 8230                task_store.task_context_for_location(captured_task_variables, location, cx)
 8231            })
 8232        })
 8233    }
 8234
 8235    pub fn spawn_nearest_task(
 8236        &mut self,
 8237        action: &SpawnNearestTask,
 8238        window: &mut Window,
 8239        cx: &mut Context<Self>,
 8240    ) {
 8241        let Some((workspace, _)) = self.workspace.clone() else {
 8242            return;
 8243        };
 8244        let Some(project) = self.project.clone() else {
 8245            return;
 8246        };
 8247
 8248        // Try to find a closest, enclosing node using tree-sitter that has a task
 8249        let Some((buffer, buffer_row, tasks)) = self
 8250            .find_enclosing_node_task(cx)
 8251            // Or find the task that's closest in row-distance.
 8252            .or_else(|| self.find_closest_task(cx))
 8253        else {
 8254            return;
 8255        };
 8256
 8257        let reveal_strategy = action.reveal;
 8258        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8259        cx.spawn_in(window, async move |_, cx| {
 8260            let context = task_context.await?;
 8261            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8262
 8263            let resolved = &mut resolved_task.resolved;
 8264            resolved.reveal = reveal_strategy;
 8265
 8266            workspace
 8267                .update_in(cx, |workspace, window, cx| {
 8268                    workspace.schedule_resolved_task(
 8269                        task_source_kind,
 8270                        resolved_task,
 8271                        false,
 8272                        window,
 8273                        cx,
 8274                    );
 8275                })
 8276                .ok()
 8277        })
 8278        .detach();
 8279    }
 8280
 8281    fn find_closest_task(
 8282        &mut self,
 8283        cx: &mut Context<Self>,
 8284    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8285        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8286
 8287        let ((buffer_id, row), tasks) = self
 8288            .tasks
 8289            .iter()
 8290            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8291
 8292        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8293        let tasks = Arc::new(tasks.to_owned());
 8294        Some((buffer, *row, tasks))
 8295    }
 8296
 8297    fn find_enclosing_node_task(
 8298        &mut self,
 8299        cx: &mut Context<Self>,
 8300    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8301        let snapshot = self.buffer.read(cx).snapshot(cx);
 8302        let offset = self.selections.newest::<usize>(cx).head();
 8303        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8304        let buffer_id = excerpt.buffer().remote_id();
 8305
 8306        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8307        let mut cursor = layer.node().walk();
 8308
 8309        while cursor.goto_first_child_for_byte(offset).is_some() {
 8310            if cursor.node().end_byte() == offset {
 8311                cursor.goto_next_sibling();
 8312            }
 8313        }
 8314
 8315        // Ascend to the smallest ancestor that contains the range and has a task.
 8316        loop {
 8317            let node = cursor.node();
 8318            let node_range = node.byte_range();
 8319            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8320
 8321            // Check if this node contains our offset
 8322            if node_range.start <= offset && node_range.end >= offset {
 8323                // If it contains offset, check for task
 8324                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8325                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8326                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8327                }
 8328            }
 8329
 8330            if !cursor.goto_parent() {
 8331                break;
 8332            }
 8333        }
 8334        None
 8335    }
 8336
 8337    fn render_run_indicator(
 8338        &self,
 8339        _style: &EditorStyle,
 8340        is_active: bool,
 8341        row: DisplayRow,
 8342        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8343        cx: &mut Context<Self>,
 8344    ) -> IconButton {
 8345        let color = Color::Muted;
 8346        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8347
 8348        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8349            .shape(ui::IconButtonShape::Square)
 8350            .icon_size(IconSize::XSmall)
 8351            .icon_color(color)
 8352            .toggle_state(is_active)
 8353            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8354                let quick_launch = e.down.button == MouseButton::Left;
 8355                window.focus(&editor.focus_handle(cx));
 8356                editor.toggle_code_actions(
 8357                    &ToggleCodeActions {
 8358                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8359                        quick_launch,
 8360                    },
 8361                    window,
 8362                    cx,
 8363                );
 8364            }))
 8365            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8366                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8367            }))
 8368    }
 8369
 8370    pub fn context_menu_visible(&self) -> bool {
 8371        !self.edit_prediction_preview_is_active()
 8372            && self
 8373                .context_menu
 8374                .borrow()
 8375                .as_ref()
 8376                .map_or(false, |menu| menu.visible())
 8377    }
 8378
 8379    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8380        self.context_menu
 8381            .borrow()
 8382            .as_ref()
 8383            .map(|menu| menu.origin())
 8384    }
 8385
 8386    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8387        self.context_menu_options = Some(options);
 8388    }
 8389
 8390    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8391    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8392
 8393    fn render_edit_prediction_popover(
 8394        &mut self,
 8395        text_bounds: &Bounds<Pixels>,
 8396        content_origin: gpui::Point<Pixels>,
 8397        right_margin: Pixels,
 8398        editor_snapshot: &EditorSnapshot,
 8399        visible_row_range: Range<DisplayRow>,
 8400        scroll_top: f32,
 8401        scroll_bottom: f32,
 8402        line_layouts: &[LineWithInvisibles],
 8403        line_height: Pixels,
 8404        scroll_pixel_position: gpui::Point<Pixels>,
 8405        newest_selection_head: Option<DisplayPoint>,
 8406        editor_width: Pixels,
 8407        style: &EditorStyle,
 8408        window: &mut Window,
 8409        cx: &mut App,
 8410    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8411        if self.mode().is_minimap() {
 8412            return None;
 8413        }
 8414        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8415
 8416        if self.edit_prediction_visible_in_cursor_popover(true) {
 8417            return None;
 8418        }
 8419
 8420        match &active_inline_completion.completion {
 8421            InlineCompletion::Move { target, .. } => {
 8422                let target_display_point = target.to_display_point(editor_snapshot);
 8423
 8424                if self.edit_prediction_requires_modifier() {
 8425                    if !self.edit_prediction_preview_is_active() {
 8426                        return None;
 8427                    }
 8428
 8429                    self.render_edit_prediction_modifier_jump_popover(
 8430                        text_bounds,
 8431                        content_origin,
 8432                        visible_row_range,
 8433                        line_layouts,
 8434                        line_height,
 8435                        scroll_pixel_position,
 8436                        newest_selection_head,
 8437                        target_display_point,
 8438                        window,
 8439                        cx,
 8440                    )
 8441                } else {
 8442                    self.render_edit_prediction_eager_jump_popover(
 8443                        text_bounds,
 8444                        content_origin,
 8445                        editor_snapshot,
 8446                        visible_row_range,
 8447                        scroll_top,
 8448                        scroll_bottom,
 8449                        line_height,
 8450                        scroll_pixel_position,
 8451                        target_display_point,
 8452                        editor_width,
 8453                        window,
 8454                        cx,
 8455                    )
 8456                }
 8457            }
 8458            InlineCompletion::Edit {
 8459                display_mode: EditDisplayMode::Inline,
 8460                ..
 8461            } => None,
 8462            InlineCompletion::Edit {
 8463                display_mode: EditDisplayMode::TabAccept,
 8464                edits,
 8465                ..
 8466            } => {
 8467                let range = &edits.first()?.0;
 8468                let target_display_point = range.end.to_display_point(editor_snapshot);
 8469
 8470                self.render_edit_prediction_end_of_line_popover(
 8471                    "Accept",
 8472                    editor_snapshot,
 8473                    visible_row_range,
 8474                    target_display_point,
 8475                    line_height,
 8476                    scroll_pixel_position,
 8477                    content_origin,
 8478                    editor_width,
 8479                    window,
 8480                    cx,
 8481                )
 8482            }
 8483            InlineCompletion::Edit {
 8484                edits,
 8485                edit_preview,
 8486                display_mode: EditDisplayMode::DiffPopover,
 8487                snapshot,
 8488            } => self.render_edit_prediction_diff_popover(
 8489                text_bounds,
 8490                content_origin,
 8491                right_margin,
 8492                editor_snapshot,
 8493                visible_row_range,
 8494                line_layouts,
 8495                line_height,
 8496                scroll_pixel_position,
 8497                newest_selection_head,
 8498                editor_width,
 8499                style,
 8500                edits,
 8501                edit_preview,
 8502                snapshot,
 8503                window,
 8504                cx,
 8505            ),
 8506        }
 8507    }
 8508
 8509    fn render_edit_prediction_modifier_jump_popover(
 8510        &mut self,
 8511        text_bounds: &Bounds<Pixels>,
 8512        content_origin: gpui::Point<Pixels>,
 8513        visible_row_range: Range<DisplayRow>,
 8514        line_layouts: &[LineWithInvisibles],
 8515        line_height: Pixels,
 8516        scroll_pixel_position: gpui::Point<Pixels>,
 8517        newest_selection_head: Option<DisplayPoint>,
 8518        target_display_point: DisplayPoint,
 8519        window: &mut Window,
 8520        cx: &mut App,
 8521    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8522        let scrolled_content_origin =
 8523            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8524
 8525        const SCROLL_PADDING_Y: Pixels = px(12.);
 8526
 8527        if target_display_point.row() < visible_row_range.start {
 8528            return self.render_edit_prediction_scroll_popover(
 8529                |_| SCROLL_PADDING_Y,
 8530                IconName::ArrowUp,
 8531                visible_row_range,
 8532                line_layouts,
 8533                newest_selection_head,
 8534                scrolled_content_origin,
 8535                window,
 8536                cx,
 8537            );
 8538        } else if target_display_point.row() >= visible_row_range.end {
 8539            return self.render_edit_prediction_scroll_popover(
 8540                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8541                IconName::ArrowDown,
 8542                visible_row_range,
 8543                line_layouts,
 8544                newest_selection_head,
 8545                scrolled_content_origin,
 8546                window,
 8547                cx,
 8548            );
 8549        }
 8550
 8551        const POLE_WIDTH: Pixels = px(2.);
 8552
 8553        let line_layout =
 8554            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8555        let target_column = target_display_point.column() as usize;
 8556
 8557        let target_x = line_layout.x_for_index(target_column);
 8558        let target_y =
 8559            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8560
 8561        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8562
 8563        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8564        border_color.l += 0.001;
 8565
 8566        let mut element = v_flex()
 8567            .items_end()
 8568            .when(flag_on_right, |el| el.items_start())
 8569            .child(if flag_on_right {
 8570                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8571                    .rounded_bl(px(0.))
 8572                    .rounded_tl(px(0.))
 8573                    .border_l_2()
 8574                    .border_color(border_color)
 8575            } else {
 8576                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8577                    .rounded_br(px(0.))
 8578                    .rounded_tr(px(0.))
 8579                    .border_r_2()
 8580                    .border_color(border_color)
 8581            })
 8582            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8583            .into_any();
 8584
 8585        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8586
 8587        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8588            - point(
 8589                if flag_on_right {
 8590                    POLE_WIDTH
 8591                } else {
 8592                    size.width - POLE_WIDTH
 8593                },
 8594                size.height - line_height,
 8595            );
 8596
 8597        origin.x = origin.x.max(content_origin.x);
 8598
 8599        element.prepaint_at(origin, window, cx);
 8600
 8601        Some((element, origin))
 8602    }
 8603
 8604    fn render_edit_prediction_scroll_popover(
 8605        &mut self,
 8606        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8607        scroll_icon: IconName,
 8608        visible_row_range: Range<DisplayRow>,
 8609        line_layouts: &[LineWithInvisibles],
 8610        newest_selection_head: Option<DisplayPoint>,
 8611        scrolled_content_origin: gpui::Point<Pixels>,
 8612        window: &mut Window,
 8613        cx: &mut App,
 8614    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8615        let mut element = self
 8616            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8617            .into_any();
 8618
 8619        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8620
 8621        let cursor = newest_selection_head?;
 8622        let cursor_row_layout =
 8623            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8624        let cursor_column = cursor.column() as usize;
 8625
 8626        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8627
 8628        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8629
 8630        element.prepaint_at(origin, window, cx);
 8631        Some((element, origin))
 8632    }
 8633
 8634    fn render_edit_prediction_eager_jump_popover(
 8635        &mut self,
 8636        text_bounds: &Bounds<Pixels>,
 8637        content_origin: gpui::Point<Pixels>,
 8638        editor_snapshot: &EditorSnapshot,
 8639        visible_row_range: Range<DisplayRow>,
 8640        scroll_top: f32,
 8641        scroll_bottom: f32,
 8642        line_height: Pixels,
 8643        scroll_pixel_position: gpui::Point<Pixels>,
 8644        target_display_point: DisplayPoint,
 8645        editor_width: Pixels,
 8646        window: &mut Window,
 8647        cx: &mut App,
 8648    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8649        if target_display_point.row().as_f32() < scroll_top {
 8650            let mut element = self
 8651                .render_edit_prediction_line_popover(
 8652                    "Jump to Edit",
 8653                    Some(IconName::ArrowUp),
 8654                    window,
 8655                    cx,
 8656                )?
 8657                .into_any();
 8658
 8659            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8660            let offset = point(
 8661                (text_bounds.size.width - size.width) / 2.,
 8662                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8663            );
 8664
 8665            let origin = text_bounds.origin + offset;
 8666            element.prepaint_at(origin, window, cx);
 8667            Some((element, origin))
 8668        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8669            let mut element = self
 8670                .render_edit_prediction_line_popover(
 8671                    "Jump to Edit",
 8672                    Some(IconName::ArrowDown),
 8673                    window,
 8674                    cx,
 8675                )?
 8676                .into_any();
 8677
 8678            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8679            let offset = point(
 8680                (text_bounds.size.width - size.width) / 2.,
 8681                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8682            );
 8683
 8684            let origin = text_bounds.origin + offset;
 8685            element.prepaint_at(origin, window, cx);
 8686            Some((element, origin))
 8687        } else {
 8688            self.render_edit_prediction_end_of_line_popover(
 8689                "Jump to Edit",
 8690                editor_snapshot,
 8691                visible_row_range,
 8692                target_display_point,
 8693                line_height,
 8694                scroll_pixel_position,
 8695                content_origin,
 8696                editor_width,
 8697                window,
 8698                cx,
 8699            )
 8700        }
 8701    }
 8702
 8703    fn render_edit_prediction_end_of_line_popover(
 8704        self: &mut Editor,
 8705        label: &'static str,
 8706        editor_snapshot: &EditorSnapshot,
 8707        visible_row_range: Range<DisplayRow>,
 8708        target_display_point: DisplayPoint,
 8709        line_height: Pixels,
 8710        scroll_pixel_position: gpui::Point<Pixels>,
 8711        content_origin: gpui::Point<Pixels>,
 8712        editor_width: Pixels,
 8713        window: &mut Window,
 8714        cx: &mut App,
 8715    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8716        let target_line_end = DisplayPoint::new(
 8717            target_display_point.row(),
 8718            editor_snapshot.line_len(target_display_point.row()),
 8719        );
 8720
 8721        let mut element = self
 8722            .render_edit_prediction_line_popover(label, None, window, cx)?
 8723            .into_any();
 8724
 8725        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8726
 8727        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8728
 8729        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8730        let mut origin = start_point
 8731            + line_origin
 8732            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8733        origin.x = origin.x.max(content_origin.x);
 8734
 8735        let max_x = content_origin.x + editor_width - size.width;
 8736
 8737        if origin.x > max_x {
 8738            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8739
 8740            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8741                origin.y += offset;
 8742                IconName::ArrowUp
 8743            } else {
 8744                origin.y -= offset;
 8745                IconName::ArrowDown
 8746            };
 8747
 8748            element = self
 8749                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8750                .into_any();
 8751
 8752            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8753
 8754            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8755        }
 8756
 8757        element.prepaint_at(origin, window, cx);
 8758        Some((element, origin))
 8759    }
 8760
 8761    fn render_edit_prediction_diff_popover(
 8762        self: &Editor,
 8763        text_bounds: &Bounds<Pixels>,
 8764        content_origin: gpui::Point<Pixels>,
 8765        right_margin: Pixels,
 8766        editor_snapshot: &EditorSnapshot,
 8767        visible_row_range: Range<DisplayRow>,
 8768        line_layouts: &[LineWithInvisibles],
 8769        line_height: Pixels,
 8770        scroll_pixel_position: gpui::Point<Pixels>,
 8771        newest_selection_head: Option<DisplayPoint>,
 8772        editor_width: Pixels,
 8773        style: &EditorStyle,
 8774        edits: &Vec<(Range<Anchor>, String)>,
 8775        edit_preview: &Option<language::EditPreview>,
 8776        snapshot: &language::BufferSnapshot,
 8777        window: &mut Window,
 8778        cx: &mut App,
 8779    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8780        let edit_start = edits
 8781            .first()
 8782            .unwrap()
 8783            .0
 8784            .start
 8785            .to_display_point(editor_snapshot);
 8786        let edit_end = edits
 8787            .last()
 8788            .unwrap()
 8789            .0
 8790            .end
 8791            .to_display_point(editor_snapshot);
 8792
 8793        let is_visible = visible_row_range.contains(&edit_start.row())
 8794            || visible_row_range.contains(&edit_end.row());
 8795        if !is_visible {
 8796            return None;
 8797        }
 8798
 8799        let highlighted_edits =
 8800            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8801
 8802        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8803        let line_count = highlighted_edits.text.lines().count();
 8804
 8805        const BORDER_WIDTH: Pixels = px(1.);
 8806
 8807        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8808        let has_keybind = keybind.is_some();
 8809
 8810        let mut element = h_flex()
 8811            .items_start()
 8812            .child(
 8813                h_flex()
 8814                    .bg(cx.theme().colors().editor_background)
 8815                    .border(BORDER_WIDTH)
 8816                    .shadow_xs()
 8817                    .border_color(cx.theme().colors().border)
 8818                    .rounded_l_lg()
 8819                    .when(line_count > 1, |el| el.rounded_br_lg())
 8820                    .pr_1()
 8821                    .child(styled_text),
 8822            )
 8823            .child(
 8824                h_flex()
 8825                    .h(line_height + BORDER_WIDTH * 2.)
 8826                    .px_1p5()
 8827                    .gap_1()
 8828                    // Workaround: For some reason, there's a gap if we don't do this
 8829                    .ml(-BORDER_WIDTH)
 8830                    .shadow(vec![gpui::BoxShadow {
 8831                        color: gpui::black().opacity(0.05),
 8832                        offset: point(px(1.), px(1.)),
 8833                        blur_radius: px(2.),
 8834                        spread_radius: px(0.),
 8835                    }])
 8836                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8837                    .border(BORDER_WIDTH)
 8838                    .border_color(cx.theme().colors().border)
 8839                    .rounded_r_lg()
 8840                    .id("edit_prediction_diff_popover_keybind")
 8841                    .when(!has_keybind, |el| {
 8842                        let status_colors = cx.theme().status();
 8843
 8844                        el.bg(status_colors.error_background)
 8845                            .border_color(status_colors.error.opacity(0.6))
 8846                            .child(Icon::new(IconName::Info).color(Color::Error))
 8847                            .cursor_default()
 8848                            .hoverable_tooltip(move |_window, cx| {
 8849                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8850                            })
 8851                    })
 8852                    .children(keybind),
 8853            )
 8854            .into_any();
 8855
 8856        let longest_row =
 8857            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8858        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8859            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8860        } else {
 8861            layout_line(
 8862                longest_row,
 8863                editor_snapshot,
 8864                style,
 8865                editor_width,
 8866                |_| false,
 8867                window,
 8868                cx,
 8869            )
 8870            .width
 8871        };
 8872
 8873        let viewport_bounds =
 8874            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8875                right: -right_margin,
 8876                ..Default::default()
 8877            });
 8878
 8879        let x_after_longest =
 8880            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8881                - scroll_pixel_position.x;
 8882
 8883        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8884
 8885        // Fully visible if it can be displayed within the window (allow overlapping other
 8886        // panes). However, this is only allowed if the popover starts within text_bounds.
 8887        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8888            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8889
 8890        let mut origin = if can_position_to_the_right {
 8891            point(
 8892                x_after_longest,
 8893                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8894                    - scroll_pixel_position.y,
 8895            )
 8896        } else {
 8897            let cursor_row = newest_selection_head.map(|head| head.row());
 8898            let above_edit = edit_start
 8899                .row()
 8900                .0
 8901                .checked_sub(line_count as u32)
 8902                .map(DisplayRow);
 8903            let below_edit = Some(edit_end.row() + 1);
 8904            let above_cursor =
 8905                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8906            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8907
 8908            // Place the edit popover adjacent to the edit if there is a location
 8909            // available that is onscreen and does not obscure the cursor. Otherwise,
 8910            // place it adjacent to the cursor.
 8911            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8912                .into_iter()
 8913                .flatten()
 8914                .find(|&start_row| {
 8915                    let end_row = start_row + line_count as u32;
 8916                    visible_row_range.contains(&start_row)
 8917                        && visible_row_range.contains(&end_row)
 8918                        && cursor_row.map_or(true, |cursor_row| {
 8919                            !((start_row..end_row).contains(&cursor_row))
 8920                        })
 8921                })?;
 8922
 8923            content_origin
 8924                + point(
 8925                    -scroll_pixel_position.x,
 8926                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8927                )
 8928        };
 8929
 8930        origin.x -= BORDER_WIDTH;
 8931
 8932        window.defer_draw(element, origin, 1);
 8933
 8934        // Do not return an element, since it will already be drawn due to defer_draw.
 8935        None
 8936    }
 8937
 8938    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8939        px(30.)
 8940    }
 8941
 8942    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8943        if self.read_only(cx) {
 8944            cx.theme().players().read_only()
 8945        } else {
 8946            self.style.as_ref().unwrap().local_player
 8947        }
 8948    }
 8949
 8950    fn render_edit_prediction_accept_keybind(
 8951        &self,
 8952        window: &mut Window,
 8953        cx: &App,
 8954    ) -> Option<AnyElement> {
 8955        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8956        let accept_keystroke = accept_binding.keystroke()?;
 8957
 8958        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8959
 8960        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8961            Color::Accent
 8962        } else {
 8963            Color::Muted
 8964        };
 8965
 8966        h_flex()
 8967            .px_0p5()
 8968            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8969            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8970            .text_size(TextSize::XSmall.rems(cx))
 8971            .child(h_flex().children(ui::render_modifiers(
 8972                &accept_keystroke.modifiers,
 8973                PlatformStyle::platform(),
 8974                Some(modifiers_color),
 8975                Some(IconSize::XSmall.rems().into()),
 8976                true,
 8977            )))
 8978            .when(is_platform_style_mac, |parent| {
 8979                parent.child(accept_keystroke.key.clone())
 8980            })
 8981            .when(!is_platform_style_mac, |parent| {
 8982                parent.child(
 8983                    Key::new(
 8984                        util::capitalize(&accept_keystroke.key),
 8985                        Some(Color::Default),
 8986                    )
 8987                    .size(Some(IconSize::XSmall.rems().into())),
 8988                )
 8989            })
 8990            .into_any()
 8991            .into()
 8992    }
 8993
 8994    fn render_edit_prediction_line_popover(
 8995        &self,
 8996        label: impl Into<SharedString>,
 8997        icon: Option<IconName>,
 8998        window: &mut Window,
 8999        cx: &App,
 9000    ) -> Option<Stateful<Div>> {
 9001        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9002
 9003        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9004        let has_keybind = keybind.is_some();
 9005
 9006        let result = h_flex()
 9007            .id("ep-line-popover")
 9008            .py_0p5()
 9009            .pl_1()
 9010            .pr(padding_right)
 9011            .gap_1()
 9012            .rounded_md()
 9013            .border_1()
 9014            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9015            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9016            .shadow_xs()
 9017            .when(!has_keybind, |el| {
 9018                let status_colors = cx.theme().status();
 9019
 9020                el.bg(status_colors.error_background)
 9021                    .border_color(status_colors.error.opacity(0.6))
 9022                    .pl_2()
 9023                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9024                    .cursor_default()
 9025                    .hoverable_tooltip(move |_window, cx| {
 9026                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9027                    })
 9028            })
 9029            .children(keybind)
 9030            .child(
 9031                Label::new(label)
 9032                    .size(LabelSize::Small)
 9033                    .when(!has_keybind, |el| {
 9034                        el.color(cx.theme().status().error.into()).strikethrough()
 9035                    }),
 9036            )
 9037            .when(!has_keybind, |el| {
 9038                el.child(
 9039                    h_flex().ml_1().child(
 9040                        Icon::new(IconName::Info)
 9041                            .size(IconSize::Small)
 9042                            .color(cx.theme().status().error.into()),
 9043                    ),
 9044                )
 9045            })
 9046            .when_some(icon, |element, icon| {
 9047                element.child(
 9048                    div()
 9049                        .mt(px(1.5))
 9050                        .child(Icon::new(icon).size(IconSize::Small)),
 9051                )
 9052            });
 9053
 9054        Some(result)
 9055    }
 9056
 9057    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9058        let accent_color = cx.theme().colors().text_accent;
 9059        let editor_bg_color = cx.theme().colors().editor_background;
 9060        editor_bg_color.blend(accent_color.opacity(0.1))
 9061    }
 9062
 9063    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9064        let accent_color = cx.theme().colors().text_accent;
 9065        let editor_bg_color = cx.theme().colors().editor_background;
 9066        editor_bg_color.blend(accent_color.opacity(0.6))
 9067    }
 9068
 9069    fn render_edit_prediction_cursor_popover(
 9070        &self,
 9071        min_width: Pixels,
 9072        max_width: Pixels,
 9073        cursor_point: Point,
 9074        style: &EditorStyle,
 9075        accept_keystroke: Option<&gpui::Keystroke>,
 9076        _window: &Window,
 9077        cx: &mut Context<Editor>,
 9078    ) -> Option<AnyElement> {
 9079        let provider = self.edit_prediction_provider.as_ref()?;
 9080
 9081        if provider.provider.needs_terms_acceptance(cx) {
 9082            return Some(
 9083                h_flex()
 9084                    .min_w(min_width)
 9085                    .flex_1()
 9086                    .px_2()
 9087                    .py_1()
 9088                    .gap_3()
 9089                    .elevation_2(cx)
 9090                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9091                    .id("accept-terms")
 9092                    .cursor_pointer()
 9093                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9094                    .on_click(cx.listener(|this, _event, window, cx| {
 9095                        cx.stop_propagation();
 9096                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9097                        window.dispatch_action(
 9098                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9099                            cx,
 9100                        );
 9101                    }))
 9102                    .child(
 9103                        h_flex()
 9104                            .flex_1()
 9105                            .gap_2()
 9106                            .child(Icon::new(IconName::ZedPredict))
 9107                            .child(Label::new("Accept Terms of Service"))
 9108                            .child(div().w_full())
 9109                            .child(
 9110                                Icon::new(IconName::ArrowUpRight)
 9111                                    .color(Color::Muted)
 9112                                    .size(IconSize::Small),
 9113                            )
 9114                            .into_any_element(),
 9115                    )
 9116                    .into_any(),
 9117            );
 9118        }
 9119
 9120        let is_refreshing = provider.provider.is_refreshing(cx);
 9121
 9122        fn pending_completion_container() -> Div {
 9123            h_flex()
 9124                .h_full()
 9125                .flex_1()
 9126                .gap_2()
 9127                .child(Icon::new(IconName::ZedPredict))
 9128        }
 9129
 9130        let completion = match &self.active_inline_completion {
 9131            Some(prediction) => {
 9132                if !self.has_visible_completions_menu() {
 9133                    const RADIUS: Pixels = px(6.);
 9134                    const BORDER_WIDTH: Pixels = px(1.);
 9135
 9136                    return Some(
 9137                        h_flex()
 9138                            .elevation_2(cx)
 9139                            .border(BORDER_WIDTH)
 9140                            .border_color(cx.theme().colors().border)
 9141                            .when(accept_keystroke.is_none(), |el| {
 9142                                el.border_color(cx.theme().status().error)
 9143                            })
 9144                            .rounded(RADIUS)
 9145                            .rounded_tl(px(0.))
 9146                            .overflow_hidden()
 9147                            .child(div().px_1p5().child(match &prediction.completion {
 9148                                InlineCompletion::Move { target, snapshot } => {
 9149                                    use text::ToPoint as _;
 9150                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9151                                    {
 9152                                        Icon::new(IconName::ZedPredictDown)
 9153                                    } else {
 9154                                        Icon::new(IconName::ZedPredictUp)
 9155                                    }
 9156                                }
 9157                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9158                            }))
 9159                            .child(
 9160                                h_flex()
 9161                                    .gap_1()
 9162                                    .py_1()
 9163                                    .px_2()
 9164                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9165                                    .border_l_1()
 9166                                    .border_color(cx.theme().colors().border)
 9167                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9168                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9169                                        el.child(
 9170                                            Label::new("Hold")
 9171                                                .size(LabelSize::Small)
 9172                                                .when(accept_keystroke.is_none(), |el| {
 9173                                                    el.strikethrough()
 9174                                                })
 9175                                                .line_height_style(LineHeightStyle::UiLabel),
 9176                                        )
 9177                                    })
 9178                                    .id("edit_prediction_cursor_popover_keybind")
 9179                                    .when(accept_keystroke.is_none(), |el| {
 9180                                        let status_colors = cx.theme().status();
 9181
 9182                                        el.bg(status_colors.error_background)
 9183                                            .border_color(status_colors.error.opacity(0.6))
 9184                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9185                                            .cursor_default()
 9186                                            .hoverable_tooltip(move |_window, cx| {
 9187                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9188                                                    .into()
 9189                                            })
 9190                                    })
 9191                                    .when_some(
 9192                                        accept_keystroke.as_ref(),
 9193                                        |el, accept_keystroke| {
 9194                                            el.child(h_flex().children(ui::render_modifiers(
 9195                                                &accept_keystroke.modifiers,
 9196                                                PlatformStyle::platform(),
 9197                                                Some(Color::Default),
 9198                                                Some(IconSize::XSmall.rems().into()),
 9199                                                false,
 9200                                            )))
 9201                                        },
 9202                                    ),
 9203                            )
 9204                            .into_any(),
 9205                    );
 9206                }
 9207
 9208                self.render_edit_prediction_cursor_popover_preview(
 9209                    prediction,
 9210                    cursor_point,
 9211                    style,
 9212                    cx,
 9213                )?
 9214            }
 9215
 9216            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9217                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9218                    stale_completion,
 9219                    cursor_point,
 9220                    style,
 9221                    cx,
 9222                )?,
 9223
 9224                None => {
 9225                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9226                }
 9227            },
 9228
 9229            None => pending_completion_container().child(Label::new("No Prediction")),
 9230        };
 9231
 9232        let completion = if is_refreshing {
 9233            completion
 9234                .with_animation(
 9235                    "loading-completion",
 9236                    Animation::new(Duration::from_secs(2))
 9237                        .repeat()
 9238                        .with_easing(pulsating_between(0.4, 0.8)),
 9239                    |label, delta| label.opacity(delta),
 9240                )
 9241                .into_any_element()
 9242        } else {
 9243            completion.into_any_element()
 9244        };
 9245
 9246        let has_completion = self.active_inline_completion.is_some();
 9247
 9248        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9249        Some(
 9250            h_flex()
 9251                .min_w(min_width)
 9252                .max_w(max_width)
 9253                .flex_1()
 9254                .elevation_2(cx)
 9255                .border_color(cx.theme().colors().border)
 9256                .child(
 9257                    div()
 9258                        .flex_1()
 9259                        .py_1()
 9260                        .px_2()
 9261                        .overflow_hidden()
 9262                        .child(completion),
 9263                )
 9264                .when_some(accept_keystroke, |el, accept_keystroke| {
 9265                    if !accept_keystroke.modifiers.modified() {
 9266                        return el;
 9267                    }
 9268
 9269                    el.child(
 9270                        h_flex()
 9271                            .h_full()
 9272                            .border_l_1()
 9273                            .rounded_r_lg()
 9274                            .border_color(cx.theme().colors().border)
 9275                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9276                            .gap_1()
 9277                            .py_1()
 9278                            .px_2()
 9279                            .child(
 9280                                h_flex()
 9281                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9282                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9283                                    .child(h_flex().children(ui::render_modifiers(
 9284                                        &accept_keystroke.modifiers,
 9285                                        PlatformStyle::platform(),
 9286                                        Some(if !has_completion {
 9287                                            Color::Muted
 9288                                        } else {
 9289                                            Color::Default
 9290                                        }),
 9291                                        None,
 9292                                        false,
 9293                                    ))),
 9294                            )
 9295                            .child(Label::new("Preview").into_any_element())
 9296                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9297                    )
 9298                })
 9299                .into_any(),
 9300        )
 9301    }
 9302
 9303    fn render_edit_prediction_cursor_popover_preview(
 9304        &self,
 9305        completion: &InlineCompletionState,
 9306        cursor_point: Point,
 9307        style: &EditorStyle,
 9308        cx: &mut Context<Editor>,
 9309    ) -> Option<Div> {
 9310        use text::ToPoint as _;
 9311
 9312        fn render_relative_row_jump(
 9313            prefix: impl Into<String>,
 9314            current_row: u32,
 9315            target_row: u32,
 9316        ) -> Div {
 9317            let (row_diff, arrow) = if target_row < current_row {
 9318                (current_row - target_row, IconName::ArrowUp)
 9319            } else {
 9320                (target_row - current_row, IconName::ArrowDown)
 9321            };
 9322
 9323            h_flex()
 9324                .child(
 9325                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9326                        .color(Color::Muted)
 9327                        .size(LabelSize::Small),
 9328                )
 9329                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9330        }
 9331
 9332        match &completion.completion {
 9333            InlineCompletion::Move {
 9334                target, snapshot, ..
 9335            } => Some(
 9336                h_flex()
 9337                    .px_2()
 9338                    .gap_2()
 9339                    .flex_1()
 9340                    .child(
 9341                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9342                            Icon::new(IconName::ZedPredictDown)
 9343                        } else {
 9344                            Icon::new(IconName::ZedPredictUp)
 9345                        },
 9346                    )
 9347                    .child(Label::new("Jump to Edit")),
 9348            ),
 9349
 9350            InlineCompletion::Edit {
 9351                edits,
 9352                edit_preview,
 9353                snapshot,
 9354                display_mode: _,
 9355            } => {
 9356                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9357
 9358                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9359                    &snapshot,
 9360                    &edits,
 9361                    edit_preview.as_ref()?,
 9362                    true,
 9363                    cx,
 9364                )
 9365                .first_line_preview();
 9366
 9367                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9368                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9369
 9370                let preview = h_flex()
 9371                    .gap_1()
 9372                    .min_w_16()
 9373                    .child(styled_text)
 9374                    .when(has_more_lines, |parent| parent.child(""));
 9375
 9376                let left = if first_edit_row != cursor_point.row {
 9377                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9378                        .into_any_element()
 9379                } else {
 9380                    Icon::new(IconName::ZedPredict).into_any_element()
 9381                };
 9382
 9383                Some(
 9384                    h_flex()
 9385                        .h_full()
 9386                        .flex_1()
 9387                        .gap_2()
 9388                        .pr_1()
 9389                        .overflow_x_hidden()
 9390                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9391                        .child(left)
 9392                        .child(preview),
 9393                )
 9394            }
 9395        }
 9396    }
 9397
 9398    pub fn render_context_menu(
 9399        &self,
 9400        style: &EditorStyle,
 9401        max_height_in_lines: u32,
 9402        window: &mut Window,
 9403        cx: &mut Context<Editor>,
 9404    ) -> Option<AnyElement> {
 9405        let menu = self.context_menu.borrow();
 9406        let menu = menu.as_ref()?;
 9407        if !menu.visible() {
 9408            return None;
 9409        };
 9410        Some(menu.render(style, max_height_in_lines, window, cx))
 9411    }
 9412
 9413    fn render_context_menu_aside(
 9414        &mut self,
 9415        max_size: Size<Pixels>,
 9416        window: &mut Window,
 9417        cx: &mut Context<Editor>,
 9418    ) -> Option<AnyElement> {
 9419        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9420            if menu.visible() {
 9421                menu.render_aside(max_size, window, cx)
 9422            } else {
 9423                None
 9424            }
 9425        })
 9426    }
 9427
 9428    fn hide_context_menu(
 9429        &mut self,
 9430        window: &mut Window,
 9431        cx: &mut Context<Self>,
 9432    ) -> Option<CodeContextMenu> {
 9433        cx.notify();
 9434        self.completion_tasks.clear();
 9435        let context_menu = self.context_menu.borrow_mut().take();
 9436        self.stale_inline_completion_in_menu.take();
 9437        self.update_visible_inline_completion(window, cx);
 9438        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9439            if let Some(completion_provider) = &self.completion_provider {
 9440                completion_provider.selection_changed(None, window, cx);
 9441            }
 9442        }
 9443        context_menu
 9444    }
 9445
 9446    fn show_snippet_choices(
 9447        &mut self,
 9448        choices: &Vec<String>,
 9449        selection: Range<Anchor>,
 9450        cx: &mut Context<Self>,
 9451    ) {
 9452        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9453            (Some(a), Some(b)) if a == b => a,
 9454            _ => {
 9455                log::error!("expected anchor range to have matching buffer IDs");
 9456                return;
 9457            }
 9458        };
 9459        let multi_buffer = self.buffer().read(cx);
 9460        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9461            return;
 9462        };
 9463
 9464        let id = post_inc(&mut self.next_completion_id);
 9465        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9466        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9467            CompletionsMenu::new_snippet_choices(
 9468                id,
 9469                true,
 9470                choices,
 9471                selection,
 9472                buffer,
 9473                snippet_sort_order,
 9474            ),
 9475        ));
 9476    }
 9477
 9478    pub fn insert_snippet(
 9479        &mut self,
 9480        insertion_ranges: &[Range<usize>],
 9481        snippet: Snippet,
 9482        window: &mut Window,
 9483        cx: &mut Context<Self>,
 9484    ) -> Result<()> {
 9485        struct Tabstop<T> {
 9486            is_end_tabstop: bool,
 9487            ranges: Vec<Range<T>>,
 9488            choices: Option<Vec<String>>,
 9489        }
 9490
 9491        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9492            let snippet_text: Arc<str> = snippet.text.clone().into();
 9493            let edits = insertion_ranges
 9494                .iter()
 9495                .cloned()
 9496                .map(|range| (range, snippet_text.clone()));
 9497            let autoindent_mode = AutoindentMode::Block {
 9498                original_indent_columns: Vec::new(),
 9499            };
 9500            buffer.edit(edits, Some(autoindent_mode), cx);
 9501
 9502            let snapshot = &*buffer.read(cx);
 9503            let snippet = &snippet;
 9504            snippet
 9505                .tabstops
 9506                .iter()
 9507                .map(|tabstop| {
 9508                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9509                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9510                    });
 9511                    let mut tabstop_ranges = tabstop
 9512                        .ranges
 9513                        .iter()
 9514                        .flat_map(|tabstop_range| {
 9515                            let mut delta = 0_isize;
 9516                            insertion_ranges.iter().map(move |insertion_range| {
 9517                                let insertion_start = insertion_range.start as isize + delta;
 9518                                delta +=
 9519                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9520
 9521                                let start = ((insertion_start + tabstop_range.start) as usize)
 9522                                    .min(snapshot.len());
 9523                                let end = ((insertion_start + tabstop_range.end) as usize)
 9524                                    .min(snapshot.len());
 9525                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9526                            })
 9527                        })
 9528                        .collect::<Vec<_>>();
 9529                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9530
 9531                    Tabstop {
 9532                        is_end_tabstop,
 9533                        ranges: tabstop_ranges,
 9534                        choices: tabstop.choices.clone(),
 9535                    }
 9536                })
 9537                .collect::<Vec<_>>()
 9538        });
 9539        if let Some(tabstop) = tabstops.first() {
 9540            self.change_selections(Default::default(), window, cx, |s| {
 9541                // Reverse order so that the first range is the newest created selection.
 9542                // Completions will use it and autoscroll will prioritize it.
 9543                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9544            });
 9545
 9546            if let Some(choices) = &tabstop.choices {
 9547                if let Some(selection) = tabstop.ranges.first() {
 9548                    self.show_snippet_choices(choices, selection.clone(), cx)
 9549                }
 9550            }
 9551
 9552            // If we're already at the last tabstop and it's at the end of the snippet,
 9553            // we're done, we don't need to keep the state around.
 9554            if !tabstop.is_end_tabstop {
 9555                let choices = tabstops
 9556                    .iter()
 9557                    .map(|tabstop| tabstop.choices.clone())
 9558                    .collect();
 9559
 9560                let ranges = tabstops
 9561                    .into_iter()
 9562                    .map(|tabstop| tabstop.ranges)
 9563                    .collect::<Vec<_>>();
 9564
 9565                self.snippet_stack.push(SnippetState {
 9566                    active_index: 0,
 9567                    ranges,
 9568                    choices,
 9569                });
 9570            }
 9571
 9572            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9573            if self.autoclose_regions.is_empty() {
 9574                let snapshot = self.buffer.read(cx).snapshot(cx);
 9575                let mut all_selections = self.selections.all::<Point>(cx);
 9576                for selection in &mut all_selections {
 9577                    let selection_head = selection.head();
 9578                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9579                        continue;
 9580                    };
 9581
 9582                    let mut bracket_pair = None;
 9583                    let max_lookup_length = scope
 9584                        .brackets()
 9585                        .map(|(pair, _)| {
 9586                            pair.start
 9587                                .as_str()
 9588                                .chars()
 9589                                .count()
 9590                                .max(pair.end.as_str().chars().count())
 9591                        })
 9592                        .max();
 9593                    if let Some(max_lookup_length) = max_lookup_length {
 9594                        let next_text = snapshot
 9595                            .chars_at(selection_head)
 9596                            .take(max_lookup_length)
 9597                            .collect::<String>();
 9598                        let prev_text = snapshot
 9599                            .reversed_chars_at(selection_head)
 9600                            .take(max_lookup_length)
 9601                            .collect::<String>();
 9602
 9603                        for (pair, enabled) in scope.brackets() {
 9604                            if enabled
 9605                                && pair.close
 9606                                && prev_text.starts_with(pair.start.as_str())
 9607                                && next_text.starts_with(pair.end.as_str())
 9608                            {
 9609                                bracket_pair = Some(pair.clone());
 9610                                break;
 9611                            }
 9612                        }
 9613                    }
 9614
 9615                    if let Some(pair) = bracket_pair {
 9616                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9617                        let autoclose_enabled =
 9618                            self.use_autoclose && snapshot_settings.use_autoclose;
 9619                        if autoclose_enabled {
 9620                            let start = snapshot.anchor_after(selection_head);
 9621                            let end = snapshot.anchor_after(selection_head);
 9622                            self.autoclose_regions.push(AutocloseRegion {
 9623                                selection_id: selection.id,
 9624                                range: start..end,
 9625                                pair,
 9626                            });
 9627                        }
 9628                    }
 9629                }
 9630            }
 9631        }
 9632        Ok(())
 9633    }
 9634
 9635    pub fn move_to_next_snippet_tabstop(
 9636        &mut self,
 9637        window: &mut Window,
 9638        cx: &mut Context<Self>,
 9639    ) -> bool {
 9640        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9641    }
 9642
 9643    pub fn move_to_prev_snippet_tabstop(
 9644        &mut self,
 9645        window: &mut Window,
 9646        cx: &mut Context<Self>,
 9647    ) -> bool {
 9648        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9649    }
 9650
 9651    pub fn move_to_snippet_tabstop(
 9652        &mut self,
 9653        bias: Bias,
 9654        window: &mut Window,
 9655        cx: &mut Context<Self>,
 9656    ) -> bool {
 9657        if let Some(mut snippet) = self.snippet_stack.pop() {
 9658            match bias {
 9659                Bias::Left => {
 9660                    if snippet.active_index > 0 {
 9661                        snippet.active_index -= 1;
 9662                    } else {
 9663                        self.snippet_stack.push(snippet);
 9664                        return false;
 9665                    }
 9666                }
 9667                Bias::Right => {
 9668                    if snippet.active_index + 1 < snippet.ranges.len() {
 9669                        snippet.active_index += 1;
 9670                    } else {
 9671                        self.snippet_stack.push(snippet);
 9672                        return false;
 9673                    }
 9674                }
 9675            }
 9676            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9677                self.change_selections(Default::default(), window, cx, |s| {
 9678                    // Reverse order so that the first range is the newest created selection.
 9679                    // Completions will use it and autoscroll will prioritize it.
 9680                    s.select_ranges(current_ranges.iter().rev().cloned())
 9681                });
 9682
 9683                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9684                    if let Some(selection) = current_ranges.first() {
 9685                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9686                    }
 9687                }
 9688
 9689                // If snippet state is not at the last tabstop, push it back on the stack
 9690                if snippet.active_index + 1 < snippet.ranges.len() {
 9691                    self.snippet_stack.push(snippet);
 9692                }
 9693                return true;
 9694            }
 9695        }
 9696
 9697        false
 9698    }
 9699
 9700    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9701        self.transact(window, cx, |this, window, cx| {
 9702            this.select_all(&SelectAll, window, cx);
 9703            this.insert("", window, cx);
 9704        });
 9705    }
 9706
 9707    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9709        self.transact(window, cx, |this, window, cx| {
 9710            this.select_autoclose_pair(window, cx);
 9711            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9712            if !this.linked_edit_ranges.is_empty() {
 9713                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9714                let snapshot = this.buffer.read(cx).snapshot(cx);
 9715
 9716                for selection in selections.iter() {
 9717                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9718                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9719                    if selection_start.buffer_id != selection_end.buffer_id {
 9720                        continue;
 9721                    }
 9722                    if let Some(ranges) =
 9723                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9724                    {
 9725                        for (buffer, entries) in ranges {
 9726                            linked_ranges.entry(buffer).or_default().extend(entries);
 9727                        }
 9728                    }
 9729                }
 9730            }
 9731
 9732            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9733            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9734            for selection in &mut selections {
 9735                if selection.is_empty() {
 9736                    let old_head = selection.head();
 9737                    let mut new_head =
 9738                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9739                            .to_point(&display_map);
 9740                    if let Some((buffer, line_buffer_range)) = display_map
 9741                        .buffer_snapshot
 9742                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9743                    {
 9744                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9745                        let indent_len = match indent_size.kind {
 9746                            IndentKind::Space => {
 9747                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9748                            }
 9749                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9750                        };
 9751                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9752                            let indent_len = indent_len.get();
 9753                            new_head = cmp::min(
 9754                                new_head,
 9755                                MultiBufferPoint::new(
 9756                                    old_head.row,
 9757                                    ((old_head.column - 1) / indent_len) * indent_len,
 9758                                ),
 9759                            );
 9760                        }
 9761                    }
 9762
 9763                    selection.set_head(new_head, SelectionGoal::None);
 9764                }
 9765            }
 9766
 9767            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9768            this.insert("", window, cx);
 9769            let empty_str: Arc<str> = Arc::from("");
 9770            for (buffer, edits) in linked_ranges {
 9771                let snapshot = buffer.read(cx).snapshot();
 9772                use text::ToPoint as TP;
 9773
 9774                let edits = edits
 9775                    .into_iter()
 9776                    .map(|range| {
 9777                        let end_point = TP::to_point(&range.end, &snapshot);
 9778                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9779
 9780                        if end_point == start_point {
 9781                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9782                                .saturating_sub(1);
 9783                            start_point =
 9784                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9785                        };
 9786
 9787                        (start_point..end_point, empty_str.clone())
 9788                    })
 9789                    .sorted_by_key(|(range, _)| range.start)
 9790                    .collect::<Vec<_>>();
 9791                buffer.update(cx, |this, cx| {
 9792                    this.edit(edits, None, cx);
 9793                })
 9794            }
 9795            this.refresh_inline_completion(true, false, window, cx);
 9796            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9797        });
 9798    }
 9799
 9800    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9802        self.transact(window, cx, |this, window, cx| {
 9803            this.change_selections(Default::default(), window, cx, |s| {
 9804                s.move_with(|map, selection| {
 9805                    if selection.is_empty() {
 9806                        let cursor = movement::right(map, selection.head());
 9807                        selection.end = cursor;
 9808                        selection.reversed = true;
 9809                        selection.goal = SelectionGoal::None;
 9810                    }
 9811                })
 9812            });
 9813            this.insert("", window, cx);
 9814            this.refresh_inline_completion(true, false, window, cx);
 9815        });
 9816    }
 9817
 9818    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9819        if self.mode.is_single_line() {
 9820            cx.propagate();
 9821            return;
 9822        }
 9823
 9824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9825        if self.move_to_prev_snippet_tabstop(window, cx) {
 9826            return;
 9827        }
 9828        self.outdent(&Outdent, window, cx);
 9829    }
 9830
 9831    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9832        if self.mode.is_single_line() {
 9833            cx.propagate();
 9834            return;
 9835        }
 9836
 9837        if self.move_to_next_snippet_tabstop(window, cx) {
 9838            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9839            return;
 9840        }
 9841        if self.read_only(cx) {
 9842            return;
 9843        }
 9844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9845        let mut selections = self.selections.all_adjusted(cx);
 9846        let buffer = self.buffer.read(cx);
 9847        let snapshot = buffer.snapshot(cx);
 9848        let rows_iter = selections.iter().map(|s| s.head().row);
 9849        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9850
 9851        let has_some_cursor_in_whitespace = selections
 9852            .iter()
 9853            .filter(|selection| selection.is_empty())
 9854            .any(|selection| {
 9855                let cursor = selection.head();
 9856                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9857                cursor.column < current_indent.len
 9858            });
 9859
 9860        let mut edits = Vec::new();
 9861        let mut prev_edited_row = 0;
 9862        let mut row_delta = 0;
 9863        for selection in &mut selections {
 9864            if selection.start.row != prev_edited_row {
 9865                row_delta = 0;
 9866            }
 9867            prev_edited_row = selection.end.row;
 9868
 9869            // If the selection is non-empty, then increase the indentation of the selected lines.
 9870            if !selection.is_empty() {
 9871                row_delta =
 9872                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9873                continue;
 9874            }
 9875
 9876            let cursor = selection.head();
 9877            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9878            if let Some(suggested_indent) =
 9879                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9880            {
 9881                // Don't do anything if already at suggested indent
 9882                // and there is any other cursor which is not
 9883                if has_some_cursor_in_whitespace
 9884                    && cursor.column == current_indent.len
 9885                    && current_indent.len == suggested_indent.len
 9886                {
 9887                    continue;
 9888                }
 9889
 9890                // Adjust line and move cursor to suggested indent
 9891                // if cursor is not at suggested indent
 9892                if cursor.column < suggested_indent.len
 9893                    && cursor.column <= current_indent.len
 9894                    && current_indent.len <= suggested_indent.len
 9895                {
 9896                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9897                    selection.end = selection.start;
 9898                    if row_delta == 0 {
 9899                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9900                            cursor.row,
 9901                            current_indent,
 9902                            suggested_indent,
 9903                        ));
 9904                        row_delta = suggested_indent.len - current_indent.len;
 9905                    }
 9906                    continue;
 9907                }
 9908
 9909                // If current indent is more than suggested indent
 9910                // only move cursor to current indent and skip indent
 9911                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9912                    selection.start = Point::new(cursor.row, current_indent.len);
 9913                    selection.end = selection.start;
 9914                    continue;
 9915                }
 9916            }
 9917
 9918            // Otherwise, insert a hard or soft tab.
 9919            let settings = buffer.language_settings_at(cursor, cx);
 9920            let tab_size = if settings.hard_tabs {
 9921                IndentSize::tab()
 9922            } else {
 9923                let tab_size = settings.tab_size.get();
 9924                let indent_remainder = snapshot
 9925                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9926                    .flat_map(str::chars)
 9927                    .fold(row_delta % tab_size, |counter: u32, c| {
 9928                        if c == '\t' {
 9929                            0
 9930                        } else {
 9931                            (counter + 1) % tab_size
 9932                        }
 9933                    });
 9934
 9935                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9936                IndentSize::spaces(chars_to_next_tab_stop)
 9937            };
 9938            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9939            selection.end = selection.start;
 9940            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9941            row_delta += tab_size.len;
 9942        }
 9943
 9944        self.transact(window, cx, |this, window, cx| {
 9945            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9946            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9947            this.refresh_inline_completion(true, false, window, cx);
 9948        });
 9949    }
 9950
 9951    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9952        if self.read_only(cx) {
 9953            return;
 9954        }
 9955        if self.mode.is_single_line() {
 9956            cx.propagate();
 9957            return;
 9958        }
 9959
 9960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961        let mut selections = self.selections.all::<Point>(cx);
 9962        let mut prev_edited_row = 0;
 9963        let mut row_delta = 0;
 9964        let mut edits = Vec::new();
 9965        let buffer = self.buffer.read(cx);
 9966        let snapshot = buffer.snapshot(cx);
 9967        for selection in &mut selections {
 9968            if selection.start.row != prev_edited_row {
 9969                row_delta = 0;
 9970            }
 9971            prev_edited_row = selection.end.row;
 9972
 9973            row_delta =
 9974                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9975        }
 9976
 9977        self.transact(window, cx, |this, window, cx| {
 9978            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9979            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9980        });
 9981    }
 9982
 9983    fn indent_selection(
 9984        buffer: &MultiBuffer,
 9985        snapshot: &MultiBufferSnapshot,
 9986        selection: &mut Selection<Point>,
 9987        edits: &mut Vec<(Range<Point>, String)>,
 9988        delta_for_start_row: u32,
 9989        cx: &App,
 9990    ) -> u32 {
 9991        let settings = buffer.language_settings_at(selection.start, cx);
 9992        let tab_size = settings.tab_size.get();
 9993        let indent_kind = if settings.hard_tabs {
 9994            IndentKind::Tab
 9995        } else {
 9996            IndentKind::Space
 9997        };
 9998        let mut start_row = selection.start.row;
 9999        let mut end_row = selection.end.row + 1;
10000
10001        // If a selection ends at the beginning of a line, don't indent
10002        // that last line.
10003        if selection.end.column == 0 && selection.end.row > selection.start.row {
10004            end_row -= 1;
10005        }
10006
10007        // Avoid re-indenting a row that has already been indented by a
10008        // previous selection, but still update this selection's column
10009        // to reflect that indentation.
10010        if delta_for_start_row > 0 {
10011            start_row += 1;
10012            selection.start.column += delta_for_start_row;
10013            if selection.end.row == selection.start.row {
10014                selection.end.column += delta_for_start_row;
10015            }
10016        }
10017
10018        let mut delta_for_end_row = 0;
10019        let has_multiple_rows = start_row + 1 != end_row;
10020        for row in start_row..end_row {
10021            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10022            let indent_delta = match (current_indent.kind, indent_kind) {
10023                (IndentKind::Space, IndentKind::Space) => {
10024                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10025                    IndentSize::spaces(columns_to_next_tab_stop)
10026                }
10027                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10028                (_, IndentKind::Tab) => IndentSize::tab(),
10029            };
10030
10031            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10032                0
10033            } else {
10034                selection.start.column
10035            };
10036            let row_start = Point::new(row, start);
10037            edits.push((
10038                row_start..row_start,
10039                indent_delta.chars().collect::<String>(),
10040            ));
10041
10042            // Update this selection's endpoints to reflect the indentation.
10043            if row == selection.start.row {
10044                selection.start.column += indent_delta.len;
10045            }
10046            if row == selection.end.row {
10047                selection.end.column += indent_delta.len;
10048                delta_for_end_row = indent_delta.len;
10049            }
10050        }
10051
10052        if selection.start.row == selection.end.row {
10053            delta_for_start_row + delta_for_end_row
10054        } else {
10055            delta_for_end_row
10056        }
10057    }
10058
10059    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10060        if self.read_only(cx) {
10061            return;
10062        }
10063        if self.mode.is_single_line() {
10064            cx.propagate();
10065            return;
10066        }
10067
10068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10070        let selections = self.selections.all::<Point>(cx);
10071        let mut deletion_ranges = Vec::new();
10072        let mut last_outdent = None;
10073        {
10074            let buffer = self.buffer.read(cx);
10075            let snapshot = buffer.snapshot(cx);
10076            for selection in &selections {
10077                let settings = buffer.language_settings_at(selection.start, cx);
10078                let tab_size = settings.tab_size.get();
10079                let mut rows = selection.spanned_rows(false, &display_map);
10080
10081                // Avoid re-outdenting a row that has already been outdented by a
10082                // previous selection.
10083                if let Some(last_row) = last_outdent {
10084                    if last_row == rows.start {
10085                        rows.start = rows.start.next_row();
10086                    }
10087                }
10088                let has_multiple_rows = rows.len() > 1;
10089                for row in rows.iter_rows() {
10090                    let indent_size = snapshot.indent_size_for_line(row);
10091                    if indent_size.len > 0 {
10092                        let deletion_len = match indent_size.kind {
10093                            IndentKind::Space => {
10094                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10095                                if columns_to_prev_tab_stop == 0 {
10096                                    tab_size
10097                                } else {
10098                                    columns_to_prev_tab_stop
10099                                }
10100                            }
10101                            IndentKind::Tab => 1,
10102                        };
10103                        let start = if has_multiple_rows
10104                            || deletion_len > selection.start.column
10105                            || indent_size.len < selection.start.column
10106                        {
10107                            0
10108                        } else {
10109                            selection.start.column - deletion_len
10110                        };
10111                        deletion_ranges.push(
10112                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10113                        );
10114                        last_outdent = Some(row);
10115                    }
10116                }
10117            }
10118        }
10119
10120        self.transact(window, cx, |this, window, cx| {
10121            this.buffer.update(cx, |buffer, cx| {
10122                let empty_str: Arc<str> = Arc::default();
10123                buffer.edit(
10124                    deletion_ranges
10125                        .into_iter()
10126                        .map(|range| (range, empty_str.clone())),
10127                    None,
10128                    cx,
10129                );
10130            });
10131            let selections = this.selections.all::<usize>(cx);
10132            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10133        });
10134    }
10135
10136    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10137        if self.read_only(cx) {
10138            return;
10139        }
10140        if self.mode.is_single_line() {
10141            cx.propagate();
10142            return;
10143        }
10144
10145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10146        let selections = self
10147            .selections
10148            .all::<usize>(cx)
10149            .into_iter()
10150            .map(|s| s.range());
10151
10152        self.transact(window, cx, |this, window, cx| {
10153            this.buffer.update(cx, |buffer, cx| {
10154                buffer.autoindent_ranges(selections, cx);
10155            });
10156            let selections = this.selections.all::<usize>(cx);
10157            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10158        });
10159    }
10160
10161    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10164        let selections = self.selections.all::<Point>(cx);
10165
10166        let mut new_cursors = Vec::new();
10167        let mut edit_ranges = Vec::new();
10168        let mut selections = selections.iter().peekable();
10169        while let Some(selection) = selections.next() {
10170            let mut rows = selection.spanned_rows(false, &display_map);
10171            let goal_display_column = selection.head().to_display_point(&display_map).column();
10172
10173            // Accumulate contiguous regions of rows that we want to delete.
10174            while let Some(next_selection) = selections.peek() {
10175                let next_rows = next_selection.spanned_rows(false, &display_map);
10176                if next_rows.start <= rows.end {
10177                    rows.end = next_rows.end;
10178                    selections.next().unwrap();
10179                } else {
10180                    break;
10181                }
10182            }
10183
10184            let buffer = &display_map.buffer_snapshot;
10185            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10186            let edit_end;
10187            let cursor_buffer_row;
10188            if buffer.max_point().row >= rows.end.0 {
10189                // If there's a line after the range, delete the \n from the end of the row range
10190                // and position the cursor on the next line.
10191                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10192                cursor_buffer_row = rows.end;
10193            } else {
10194                // If there isn't a line after the range, delete the \n from the line before the
10195                // start of the row range and position the cursor there.
10196                edit_start = edit_start.saturating_sub(1);
10197                edit_end = buffer.len();
10198                cursor_buffer_row = rows.start.previous_row();
10199            }
10200
10201            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10202            *cursor.column_mut() =
10203                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10204
10205            new_cursors.push((
10206                selection.id,
10207                buffer.anchor_after(cursor.to_point(&display_map)),
10208            ));
10209            edit_ranges.push(edit_start..edit_end);
10210        }
10211
10212        self.transact(window, cx, |this, window, cx| {
10213            let buffer = this.buffer.update(cx, |buffer, cx| {
10214                let empty_str: Arc<str> = Arc::default();
10215                buffer.edit(
10216                    edit_ranges
10217                        .into_iter()
10218                        .map(|range| (range, empty_str.clone())),
10219                    None,
10220                    cx,
10221                );
10222                buffer.snapshot(cx)
10223            });
10224            let new_selections = new_cursors
10225                .into_iter()
10226                .map(|(id, cursor)| {
10227                    let cursor = cursor.to_point(&buffer);
10228                    Selection {
10229                        id,
10230                        start: cursor,
10231                        end: cursor,
10232                        reversed: false,
10233                        goal: SelectionGoal::None,
10234                    }
10235                })
10236                .collect();
10237
10238            this.change_selections(Default::default(), window, cx, |s| {
10239                s.select(new_selections);
10240            });
10241        });
10242    }
10243
10244    pub fn join_lines_impl(
10245        &mut self,
10246        insert_whitespace: bool,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        if self.read_only(cx) {
10251            return;
10252        }
10253        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10254        for selection in self.selections.all::<Point>(cx) {
10255            let start = MultiBufferRow(selection.start.row);
10256            // Treat single line selections as if they include the next line. Otherwise this action
10257            // would do nothing for single line selections individual cursors.
10258            let end = if selection.start.row == selection.end.row {
10259                MultiBufferRow(selection.start.row + 1)
10260            } else {
10261                MultiBufferRow(selection.end.row)
10262            };
10263
10264            if let Some(last_row_range) = row_ranges.last_mut() {
10265                if start <= last_row_range.end {
10266                    last_row_range.end = end;
10267                    continue;
10268                }
10269            }
10270            row_ranges.push(start..end);
10271        }
10272
10273        let snapshot = self.buffer.read(cx).snapshot(cx);
10274        let mut cursor_positions = Vec::new();
10275        for row_range in &row_ranges {
10276            let anchor = snapshot.anchor_before(Point::new(
10277                row_range.end.previous_row().0,
10278                snapshot.line_len(row_range.end.previous_row()),
10279            ));
10280            cursor_positions.push(anchor..anchor);
10281        }
10282
10283        self.transact(window, cx, |this, window, cx| {
10284            for row_range in row_ranges.into_iter().rev() {
10285                for row in row_range.iter_rows().rev() {
10286                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10287                    let next_line_row = row.next_row();
10288                    let indent = snapshot.indent_size_for_line(next_line_row);
10289                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10290
10291                    let replace =
10292                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10293                            " "
10294                        } else {
10295                            ""
10296                        };
10297
10298                    this.buffer.update(cx, |buffer, cx| {
10299                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10300                    });
10301                }
10302            }
10303
10304            this.change_selections(Default::default(), window, cx, |s| {
10305                s.select_anchor_ranges(cursor_positions)
10306            });
10307        });
10308    }
10309
10310    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10312        self.join_lines_impl(true, window, cx);
10313    }
10314
10315    pub fn sort_lines_case_sensitive(
10316        &mut self,
10317        _: &SortLinesCaseSensitive,
10318        window: &mut Window,
10319        cx: &mut Context<Self>,
10320    ) {
10321        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10322    }
10323
10324    pub fn sort_lines_by_length(
10325        &mut self,
10326        _: &SortLinesByLength,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        self.manipulate_immutable_lines(window, cx, |lines| {
10331            lines.sort_by_key(|&line| line.chars().count())
10332        })
10333    }
10334
10335    pub fn sort_lines_case_insensitive(
10336        &mut self,
10337        _: &SortLinesCaseInsensitive,
10338        window: &mut Window,
10339        cx: &mut Context<Self>,
10340    ) {
10341        self.manipulate_immutable_lines(window, cx, |lines| {
10342            lines.sort_by_key(|line| line.to_lowercase())
10343        })
10344    }
10345
10346    pub fn unique_lines_case_insensitive(
10347        &mut self,
10348        _: &UniqueLinesCaseInsensitive,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        self.manipulate_immutable_lines(window, cx, |lines| {
10353            let mut seen = HashSet::default();
10354            lines.retain(|line| seen.insert(line.to_lowercase()));
10355        })
10356    }
10357
10358    pub fn unique_lines_case_sensitive(
10359        &mut self,
10360        _: &UniqueLinesCaseSensitive,
10361        window: &mut Window,
10362        cx: &mut Context<Self>,
10363    ) {
10364        self.manipulate_immutable_lines(window, cx, |lines| {
10365            let mut seen = HashSet::default();
10366            lines.retain(|line| seen.insert(*line));
10367        })
10368    }
10369
10370    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10371        let Some(project) = self.project.clone() else {
10372            return;
10373        };
10374        self.reload(project, window, cx)
10375            .detach_and_notify_err(window, cx);
10376    }
10377
10378    pub fn restore_file(
10379        &mut self,
10380        _: &::git::RestoreFile,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10385        let mut buffer_ids = HashSet::default();
10386        let snapshot = self.buffer().read(cx).snapshot(cx);
10387        for selection in self.selections.all::<usize>(cx) {
10388            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10389        }
10390
10391        let buffer = self.buffer().read(cx);
10392        let ranges = buffer_ids
10393            .into_iter()
10394            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10395            .collect::<Vec<_>>();
10396
10397        self.restore_hunks_in_ranges(ranges, window, cx);
10398    }
10399
10400    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10402        let selections = self
10403            .selections
10404            .all(cx)
10405            .into_iter()
10406            .map(|s| s.range())
10407            .collect();
10408        self.restore_hunks_in_ranges(selections, window, cx);
10409    }
10410
10411    pub fn restore_hunks_in_ranges(
10412        &mut self,
10413        ranges: Vec<Range<Point>>,
10414        window: &mut Window,
10415        cx: &mut Context<Editor>,
10416    ) {
10417        let mut revert_changes = HashMap::default();
10418        let chunk_by = self
10419            .snapshot(window, cx)
10420            .hunks_for_ranges(ranges)
10421            .into_iter()
10422            .chunk_by(|hunk| hunk.buffer_id);
10423        for (buffer_id, hunks) in &chunk_by {
10424            let hunks = hunks.collect::<Vec<_>>();
10425            for hunk in &hunks {
10426                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10427            }
10428            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10429        }
10430        drop(chunk_by);
10431        if !revert_changes.is_empty() {
10432            self.transact(window, cx, |editor, window, cx| {
10433                editor.restore(revert_changes, window, cx);
10434            });
10435        }
10436    }
10437
10438    pub fn open_active_item_in_terminal(
10439        &mut self,
10440        _: &OpenInTerminal,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10445            let project_path = buffer.read(cx).project_path(cx)?;
10446            let project = self.project.as_ref()?.read(cx);
10447            let entry = project.entry_for_path(&project_path, cx)?;
10448            let parent = match &entry.canonical_path {
10449                Some(canonical_path) => canonical_path.to_path_buf(),
10450                None => project.absolute_path(&project_path, cx)?,
10451            }
10452            .parent()?
10453            .to_path_buf();
10454            Some(parent)
10455        }) {
10456            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10457        }
10458    }
10459
10460    fn set_breakpoint_context_menu(
10461        &mut self,
10462        display_row: DisplayRow,
10463        position: Option<Anchor>,
10464        clicked_point: gpui::Point<Pixels>,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        let source = self
10469            .buffer
10470            .read(cx)
10471            .snapshot(cx)
10472            .anchor_before(Point::new(display_row.0, 0u32));
10473
10474        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10475
10476        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10477            self,
10478            source,
10479            clicked_point,
10480            context_menu,
10481            window,
10482            cx,
10483        );
10484    }
10485
10486    fn add_edit_breakpoint_block(
10487        &mut self,
10488        anchor: Anchor,
10489        breakpoint: &Breakpoint,
10490        edit_action: BreakpointPromptEditAction,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        let weak_editor = cx.weak_entity();
10495        let bp_prompt = cx.new(|cx| {
10496            BreakpointPromptEditor::new(
10497                weak_editor,
10498                anchor,
10499                breakpoint.clone(),
10500                edit_action,
10501                window,
10502                cx,
10503            )
10504        });
10505
10506        let height = bp_prompt.update(cx, |this, cx| {
10507            this.prompt
10508                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10509        });
10510        let cloned_prompt = bp_prompt.clone();
10511        let blocks = vec![BlockProperties {
10512            style: BlockStyle::Sticky,
10513            placement: BlockPlacement::Above(anchor),
10514            height: Some(height),
10515            render: Arc::new(move |cx| {
10516                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10517                cloned_prompt.clone().into_any_element()
10518            }),
10519            priority: 0,
10520        }];
10521
10522        let focus_handle = bp_prompt.focus_handle(cx);
10523        window.focus(&focus_handle);
10524
10525        let block_ids = self.insert_blocks(blocks, None, cx);
10526        bp_prompt.update(cx, |prompt, _| {
10527            prompt.add_block_ids(block_ids);
10528        });
10529    }
10530
10531    pub(crate) fn breakpoint_at_row(
10532        &self,
10533        row: u32,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) -> Option<(Anchor, Breakpoint)> {
10537        let snapshot = self.snapshot(window, cx);
10538        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10539
10540        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10541    }
10542
10543    pub(crate) fn breakpoint_at_anchor(
10544        &self,
10545        breakpoint_position: Anchor,
10546        snapshot: &EditorSnapshot,
10547        cx: &mut Context<Self>,
10548    ) -> Option<(Anchor, Breakpoint)> {
10549        let project = self.project.clone()?;
10550
10551        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10552            snapshot
10553                .buffer_snapshot
10554                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10555        })?;
10556
10557        let enclosing_excerpt = breakpoint_position.excerpt_id;
10558        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10559        let buffer_snapshot = buffer.read(cx).snapshot();
10560
10561        let row = buffer_snapshot
10562            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10563            .row;
10564
10565        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10566        let anchor_end = snapshot
10567            .buffer_snapshot
10568            .anchor_after(Point::new(row, line_len));
10569
10570        let bp = self
10571            .breakpoint_store
10572            .as_ref()?
10573            .read_with(cx, |breakpoint_store, cx| {
10574                breakpoint_store
10575                    .breakpoints(
10576                        &buffer,
10577                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10578                        &buffer_snapshot,
10579                        cx,
10580                    )
10581                    .next()
10582                    .and_then(|(bp, _)| {
10583                        let breakpoint_row = buffer_snapshot
10584                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10585                            .row;
10586
10587                        if breakpoint_row == row {
10588                            snapshot
10589                                .buffer_snapshot
10590                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10591                                .map(|position| (position, bp.bp.clone()))
10592                        } else {
10593                            None
10594                        }
10595                    })
10596            });
10597        bp
10598    }
10599
10600    pub fn edit_log_breakpoint(
10601        &mut self,
10602        _: &EditLogBreakpoint,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10607            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10608                message: None,
10609                state: BreakpointState::Enabled,
10610                condition: None,
10611                hit_condition: None,
10612            });
10613
10614            self.add_edit_breakpoint_block(
10615                anchor,
10616                &breakpoint,
10617                BreakpointPromptEditAction::Log,
10618                window,
10619                cx,
10620            );
10621        }
10622    }
10623
10624    fn breakpoints_at_cursors(
10625        &self,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10629        let snapshot = self.snapshot(window, cx);
10630        let cursors = self
10631            .selections
10632            .disjoint_anchors()
10633            .into_iter()
10634            .map(|selection| {
10635                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10636
10637                let breakpoint_position = self
10638                    .breakpoint_at_row(cursor_position.row, window, cx)
10639                    .map(|bp| bp.0)
10640                    .unwrap_or_else(|| {
10641                        snapshot
10642                            .display_snapshot
10643                            .buffer_snapshot
10644                            .anchor_after(Point::new(cursor_position.row, 0))
10645                    });
10646
10647                let breakpoint = self
10648                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10649                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10650
10651                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10652            })
10653            // 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.
10654            .collect::<HashMap<Anchor, _>>();
10655
10656        cursors.into_iter().collect()
10657    }
10658
10659    pub fn enable_breakpoint(
10660        &mut self,
10661        _: &crate::actions::EnableBreakpoint,
10662        window: &mut Window,
10663        cx: &mut Context<Self>,
10664    ) {
10665        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10666            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10667                continue;
10668            };
10669            self.edit_breakpoint_at_anchor(
10670                anchor,
10671                breakpoint,
10672                BreakpointEditAction::InvertState,
10673                cx,
10674            );
10675        }
10676    }
10677
10678    pub fn disable_breakpoint(
10679        &mut self,
10680        _: &crate::actions::DisableBreakpoint,
10681        window: &mut Window,
10682        cx: &mut Context<Self>,
10683    ) {
10684        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10685            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10686                continue;
10687            };
10688            self.edit_breakpoint_at_anchor(
10689                anchor,
10690                breakpoint,
10691                BreakpointEditAction::InvertState,
10692                cx,
10693            );
10694        }
10695    }
10696
10697    pub fn toggle_breakpoint(
10698        &mut self,
10699        _: &crate::actions::ToggleBreakpoint,
10700        window: &mut Window,
10701        cx: &mut Context<Self>,
10702    ) {
10703        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10704            if let Some(breakpoint) = breakpoint {
10705                self.edit_breakpoint_at_anchor(
10706                    anchor,
10707                    breakpoint,
10708                    BreakpointEditAction::Toggle,
10709                    cx,
10710                );
10711            } else {
10712                self.edit_breakpoint_at_anchor(
10713                    anchor,
10714                    Breakpoint::new_standard(),
10715                    BreakpointEditAction::Toggle,
10716                    cx,
10717                );
10718            }
10719        }
10720    }
10721
10722    pub fn edit_breakpoint_at_anchor(
10723        &mut self,
10724        breakpoint_position: Anchor,
10725        breakpoint: Breakpoint,
10726        edit_action: BreakpointEditAction,
10727        cx: &mut Context<Self>,
10728    ) {
10729        let Some(breakpoint_store) = &self.breakpoint_store else {
10730            return;
10731        };
10732
10733        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10734            if breakpoint_position == Anchor::min() {
10735                self.buffer()
10736                    .read(cx)
10737                    .excerpt_buffer_ids()
10738                    .into_iter()
10739                    .next()
10740            } else {
10741                None
10742            }
10743        }) else {
10744            return;
10745        };
10746
10747        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10748            return;
10749        };
10750
10751        breakpoint_store.update(cx, |breakpoint_store, cx| {
10752            breakpoint_store.toggle_breakpoint(
10753                buffer,
10754                BreakpointWithPosition {
10755                    position: breakpoint_position.text_anchor,
10756                    bp: breakpoint,
10757                },
10758                edit_action,
10759                cx,
10760            );
10761        });
10762
10763        cx.notify();
10764    }
10765
10766    #[cfg(any(test, feature = "test-support"))]
10767    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10768        self.breakpoint_store.clone()
10769    }
10770
10771    pub fn prepare_restore_change(
10772        &self,
10773        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10774        hunk: &MultiBufferDiffHunk,
10775        cx: &mut App,
10776    ) -> Option<()> {
10777        if hunk.is_created_file() {
10778            return None;
10779        }
10780        let buffer = self.buffer.read(cx);
10781        let diff = buffer.diff_for(hunk.buffer_id)?;
10782        let buffer = buffer.buffer(hunk.buffer_id)?;
10783        let buffer = buffer.read(cx);
10784        let original_text = diff
10785            .read(cx)
10786            .base_text()
10787            .as_rope()
10788            .slice(hunk.diff_base_byte_range.clone());
10789        let buffer_snapshot = buffer.snapshot();
10790        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10791        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10792            probe
10793                .0
10794                .start
10795                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10796                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10797        }) {
10798            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10799            Some(())
10800        } else {
10801            None
10802        }
10803    }
10804
10805    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10806        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10807    }
10808
10809    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10810        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10811    }
10812
10813    fn manipulate_lines<M>(
10814        &mut self,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817        mut manipulate: M,
10818    ) where
10819        M: FnMut(&str) -> LineManipulationResult,
10820    {
10821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10822
10823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10824        let buffer = self.buffer.read(cx).snapshot(cx);
10825
10826        let mut edits = Vec::new();
10827
10828        let selections = self.selections.all::<Point>(cx);
10829        let mut selections = selections.iter().peekable();
10830        let mut contiguous_row_selections = Vec::new();
10831        let mut new_selections = Vec::new();
10832        let mut added_lines = 0;
10833        let mut removed_lines = 0;
10834
10835        while let Some(selection) = selections.next() {
10836            let (start_row, end_row) = consume_contiguous_rows(
10837                &mut contiguous_row_selections,
10838                selection,
10839                &display_map,
10840                &mut selections,
10841            );
10842
10843            let start_point = Point::new(start_row.0, 0);
10844            let end_point = Point::new(
10845                end_row.previous_row().0,
10846                buffer.line_len(end_row.previous_row()),
10847            );
10848            let text = buffer
10849                .text_for_range(start_point..end_point)
10850                .collect::<String>();
10851
10852            let LineManipulationResult {
10853                new_text,
10854                line_count_before,
10855                line_count_after,
10856            } = manipulate(&text);
10857
10858            edits.push((start_point..end_point, new_text));
10859
10860            // Selections must change based on added and removed line count
10861            let start_row =
10862                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10863            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10864            new_selections.push(Selection {
10865                id: selection.id,
10866                start: start_row,
10867                end: end_row,
10868                goal: SelectionGoal::None,
10869                reversed: selection.reversed,
10870            });
10871
10872            if line_count_after > line_count_before {
10873                added_lines += line_count_after - line_count_before;
10874            } else if line_count_before > line_count_after {
10875                removed_lines += line_count_before - line_count_after;
10876            }
10877        }
10878
10879        self.transact(window, cx, |this, window, cx| {
10880            let buffer = this.buffer.update(cx, |buffer, cx| {
10881                buffer.edit(edits, None, cx);
10882                buffer.snapshot(cx)
10883            });
10884
10885            // Recalculate offsets on newly edited buffer
10886            let new_selections = new_selections
10887                .iter()
10888                .map(|s| {
10889                    let start_point = Point::new(s.start.0, 0);
10890                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10891                    Selection {
10892                        id: s.id,
10893                        start: buffer.point_to_offset(start_point),
10894                        end: buffer.point_to_offset(end_point),
10895                        goal: s.goal,
10896                        reversed: s.reversed,
10897                    }
10898                })
10899                .collect();
10900
10901            this.change_selections(Default::default(), window, cx, |s| {
10902                s.select(new_selections);
10903            });
10904
10905            this.request_autoscroll(Autoscroll::fit(), cx);
10906        });
10907    }
10908
10909    fn manipulate_immutable_lines<Fn>(
10910        &mut self,
10911        window: &mut Window,
10912        cx: &mut Context<Self>,
10913        mut callback: Fn,
10914    ) where
10915        Fn: FnMut(&mut Vec<&str>),
10916    {
10917        self.manipulate_lines(window, cx, |text| {
10918            let mut lines: Vec<&str> = text.split('\n').collect();
10919            let line_count_before = lines.len();
10920
10921            callback(&mut lines);
10922
10923            LineManipulationResult {
10924                new_text: lines.join("\n"),
10925                line_count_before,
10926                line_count_after: lines.len(),
10927            }
10928        });
10929    }
10930
10931    fn manipulate_mutable_lines<Fn>(
10932        &mut self,
10933        window: &mut Window,
10934        cx: &mut Context<Self>,
10935        mut callback: Fn,
10936    ) where
10937        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10938    {
10939        self.manipulate_lines(window, cx, |text| {
10940            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10941            let line_count_before = lines.len();
10942
10943            callback(&mut lines);
10944
10945            LineManipulationResult {
10946                new_text: lines.join("\n"),
10947                line_count_before,
10948                line_count_after: lines.len(),
10949            }
10950        });
10951    }
10952
10953    pub fn convert_indentation_to_spaces(
10954        &mut self,
10955        _: &ConvertIndentationToSpaces,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958    ) {
10959        let settings = self.buffer.read(cx).language_settings(cx);
10960        let tab_size = settings.tab_size.get() as usize;
10961
10962        self.manipulate_mutable_lines(window, cx, |lines| {
10963            // Allocates a reasonably sized scratch buffer once for the whole loop
10964            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10965            // Avoids recomputing spaces that could be inserted many times
10966            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10967                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10968                .collect();
10969
10970            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10971                let mut chars = line.as_ref().chars();
10972                let mut col = 0;
10973                let mut changed = false;
10974
10975                while let Some(ch) = chars.next() {
10976                    match ch {
10977                        ' ' => {
10978                            reindented_line.push(' ');
10979                            col += 1;
10980                        }
10981                        '\t' => {
10982                            // \t are converted to spaces depending on the current column
10983                            let spaces_len = tab_size - (col % tab_size);
10984                            reindented_line.extend(&space_cache[spaces_len - 1]);
10985                            col += spaces_len;
10986                            changed = true;
10987                        }
10988                        _ => {
10989                            // If we dont append before break, the character is consumed
10990                            reindented_line.push(ch);
10991                            break;
10992                        }
10993                    }
10994                }
10995
10996                if !changed {
10997                    reindented_line.clear();
10998                    continue;
10999                }
11000                // Append the rest of the line and replace old reference with new one
11001                reindented_line.extend(chars);
11002                *line = Cow::Owned(reindented_line.clone());
11003                reindented_line.clear();
11004            }
11005        });
11006    }
11007
11008    pub fn convert_indentation_to_tabs(
11009        &mut self,
11010        _: &ConvertIndentationToTabs,
11011        window: &mut Window,
11012        cx: &mut Context<Self>,
11013    ) {
11014        let settings = self.buffer.read(cx).language_settings(cx);
11015        let tab_size = settings.tab_size.get() as usize;
11016
11017        self.manipulate_mutable_lines(window, cx, |lines| {
11018            // Allocates a reasonably sized buffer once for the whole loop
11019            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11020            // Avoids recomputing spaces that could be inserted many times
11021            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11022                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11023                .collect();
11024
11025            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11026                let mut chars = line.chars();
11027                let mut spaces_count = 0;
11028                let mut first_non_indent_char = None;
11029                let mut changed = false;
11030
11031                while let Some(ch) = chars.next() {
11032                    match ch {
11033                        ' ' => {
11034                            // Keep track of spaces. Append \t when we reach tab_size
11035                            spaces_count += 1;
11036                            changed = true;
11037                            if spaces_count == tab_size {
11038                                reindented_line.push('\t');
11039                                spaces_count = 0;
11040                            }
11041                        }
11042                        '\t' => {
11043                            reindented_line.push('\t');
11044                            spaces_count = 0;
11045                        }
11046                        _ => {
11047                            // Dont append it yet, we might have remaining spaces
11048                            first_non_indent_char = Some(ch);
11049                            break;
11050                        }
11051                    }
11052                }
11053
11054                if !changed {
11055                    reindented_line.clear();
11056                    continue;
11057                }
11058                // Remaining spaces that didn't make a full tab stop
11059                if spaces_count > 0 {
11060                    reindented_line.extend(&space_cache[spaces_count - 1]);
11061                }
11062                // If we consume an extra character that was not indentation, add it back
11063                if let Some(extra_char) = first_non_indent_char {
11064                    reindented_line.push(extra_char);
11065                }
11066                // Append the rest of the line and replace old reference with new one
11067                reindented_line.extend(chars);
11068                *line = Cow::Owned(reindented_line.clone());
11069                reindented_line.clear();
11070            }
11071        });
11072    }
11073
11074    pub fn convert_to_upper_case(
11075        &mut self,
11076        _: &ConvertToUpperCase,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        self.manipulate_text(window, cx, |text| text.to_uppercase())
11081    }
11082
11083    pub fn convert_to_lower_case(
11084        &mut self,
11085        _: &ConvertToLowerCase,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) {
11089        self.manipulate_text(window, cx, |text| text.to_lowercase())
11090    }
11091
11092    pub fn convert_to_title_case(
11093        &mut self,
11094        _: &ConvertToTitleCase,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        self.manipulate_text(window, cx, |text| {
11099            text.split('\n')
11100                .map(|line| line.to_case(Case::Title))
11101                .join("\n")
11102        })
11103    }
11104
11105    pub fn convert_to_snake_case(
11106        &mut self,
11107        _: &ConvertToSnakeCase,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11112    }
11113
11114    pub fn convert_to_kebab_case(
11115        &mut self,
11116        _: &ConvertToKebabCase,
11117        window: &mut Window,
11118        cx: &mut Context<Self>,
11119    ) {
11120        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11121    }
11122
11123    pub fn convert_to_upper_camel_case(
11124        &mut self,
11125        _: &ConvertToUpperCamelCase,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128    ) {
11129        self.manipulate_text(window, cx, |text| {
11130            text.split('\n')
11131                .map(|line| line.to_case(Case::UpperCamel))
11132                .join("\n")
11133        })
11134    }
11135
11136    pub fn convert_to_lower_camel_case(
11137        &mut self,
11138        _: &ConvertToLowerCamelCase,
11139        window: &mut Window,
11140        cx: &mut Context<Self>,
11141    ) {
11142        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11143    }
11144
11145    pub fn convert_to_opposite_case(
11146        &mut self,
11147        _: &ConvertToOppositeCase,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        self.manipulate_text(window, cx, |text| {
11152            text.chars()
11153                .fold(String::with_capacity(text.len()), |mut t, c| {
11154                    if c.is_uppercase() {
11155                        t.extend(c.to_lowercase());
11156                    } else {
11157                        t.extend(c.to_uppercase());
11158                    }
11159                    t
11160                })
11161        })
11162    }
11163
11164    pub fn convert_to_sentence_case(
11165        &mut self,
11166        _: &ConvertToSentenceCase,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11171    }
11172
11173    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11174        self.manipulate_text(window, cx, |text| {
11175            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11176            if has_upper_case_characters {
11177                text.to_lowercase()
11178            } else {
11179                text.to_uppercase()
11180            }
11181        })
11182    }
11183
11184    pub fn convert_to_rot13(
11185        &mut self,
11186        _: &ConvertToRot13,
11187        window: &mut Window,
11188        cx: &mut Context<Self>,
11189    ) {
11190        self.manipulate_text(window, cx, |text| {
11191            text.chars()
11192                .map(|c| match c {
11193                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11194                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11195                    _ => c,
11196                })
11197                .collect()
11198        })
11199    }
11200
11201    pub fn convert_to_rot47(
11202        &mut self,
11203        _: &ConvertToRot47,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        self.manipulate_text(window, cx, |text| {
11208            text.chars()
11209                .map(|c| {
11210                    let code_point = c as u32;
11211                    if code_point >= 33 && code_point <= 126 {
11212                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11213                    }
11214                    c
11215                })
11216                .collect()
11217        })
11218    }
11219
11220    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11221    where
11222        Fn: FnMut(&str) -> String,
11223    {
11224        let buffer = self.buffer.read(cx).snapshot(cx);
11225
11226        let mut new_selections = Vec::new();
11227        let mut edits = Vec::new();
11228        let mut selection_adjustment = 0i32;
11229
11230        for selection in self.selections.all::<usize>(cx) {
11231            let selection_is_empty = selection.is_empty();
11232
11233            let (start, end) = if selection_is_empty {
11234                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11235                (word_range.start, word_range.end)
11236            } else {
11237                (selection.start, selection.end)
11238            };
11239
11240            let text = buffer.text_for_range(start..end).collect::<String>();
11241            let old_length = text.len() as i32;
11242            let text = callback(&text);
11243
11244            new_selections.push(Selection {
11245                start: (start as i32 - selection_adjustment) as usize,
11246                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11247                goal: SelectionGoal::None,
11248                ..selection
11249            });
11250
11251            selection_adjustment += old_length - text.len() as i32;
11252
11253            edits.push((start..end, text));
11254        }
11255
11256        self.transact(window, cx, |this, window, cx| {
11257            this.buffer.update(cx, |buffer, cx| {
11258                buffer.edit(edits, None, cx);
11259            });
11260
11261            this.change_selections(Default::default(), window, cx, |s| {
11262                s.select(new_selections);
11263            });
11264
11265            this.request_autoscroll(Autoscroll::fit(), cx);
11266        });
11267    }
11268
11269    pub fn move_selection_on_drop(
11270        &mut self,
11271        selection: &Selection<Anchor>,
11272        target: DisplayPoint,
11273        is_cut: bool,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11278        let buffer = &display_map.buffer_snapshot;
11279        let mut edits = Vec::new();
11280        let insert_point = display_map
11281            .clip_point(target, Bias::Left)
11282            .to_point(&display_map);
11283        let text = buffer
11284            .text_for_range(selection.start..selection.end)
11285            .collect::<String>();
11286        if is_cut {
11287            edits.push(((selection.start..selection.end), String::new()));
11288        }
11289        let insert_anchor = buffer.anchor_before(insert_point);
11290        edits.push(((insert_anchor..insert_anchor), text));
11291        let last_edit_start = insert_anchor.bias_left(buffer);
11292        let last_edit_end = insert_anchor.bias_right(buffer);
11293        self.transact(window, cx, |this, window, cx| {
11294            this.buffer.update(cx, |buffer, cx| {
11295                buffer.edit(edits, None, cx);
11296            });
11297            this.change_selections(Default::default(), window, cx, |s| {
11298                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11299            });
11300        });
11301    }
11302
11303    pub fn clear_selection_drag_state(&mut self) {
11304        self.selection_drag_state = SelectionDragState::None;
11305    }
11306
11307    pub fn duplicate(
11308        &mut self,
11309        upwards: bool,
11310        whole_lines: bool,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11315
11316        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11317        let buffer = &display_map.buffer_snapshot;
11318        let selections = self.selections.all::<Point>(cx);
11319
11320        let mut edits = Vec::new();
11321        let mut selections_iter = selections.iter().peekable();
11322        while let Some(selection) = selections_iter.next() {
11323            let mut rows = selection.spanned_rows(false, &display_map);
11324            // duplicate line-wise
11325            if whole_lines || selection.start == selection.end {
11326                // Avoid duplicating the same lines twice.
11327                while let Some(next_selection) = selections_iter.peek() {
11328                    let next_rows = next_selection.spanned_rows(false, &display_map);
11329                    if next_rows.start < rows.end {
11330                        rows.end = next_rows.end;
11331                        selections_iter.next().unwrap();
11332                    } else {
11333                        break;
11334                    }
11335                }
11336
11337                // Copy the text from the selected row region and splice it either at the start
11338                // or end of the region.
11339                let start = Point::new(rows.start.0, 0);
11340                let end = Point::new(
11341                    rows.end.previous_row().0,
11342                    buffer.line_len(rows.end.previous_row()),
11343                );
11344                let text = buffer
11345                    .text_for_range(start..end)
11346                    .chain(Some("\n"))
11347                    .collect::<String>();
11348                let insert_location = if upwards {
11349                    Point::new(rows.end.0, 0)
11350                } else {
11351                    start
11352                };
11353                edits.push((insert_location..insert_location, text));
11354            } else {
11355                // duplicate character-wise
11356                let start = selection.start;
11357                let end = selection.end;
11358                let text = buffer.text_for_range(start..end).collect::<String>();
11359                edits.push((selection.end..selection.end, text));
11360            }
11361        }
11362
11363        self.transact(window, cx, |this, _, cx| {
11364            this.buffer.update(cx, |buffer, cx| {
11365                buffer.edit(edits, None, cx);
11366            });
11367
11368            this.request_autoscroll(Autoscroll::fit(), cx);
11369        });
11370    }
11371
11372    pub fn duplicate_line_up(
11373        &mut self,
11374        _: &DuplicateLineUp,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.duplicate(true, true, window, cx);
11379    }
11380
11381    pub fn duplicate_line_down(
11382        &mut self,
11383        _: &DuplicateLineDown,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386    ) {
11387        self.duplicate(false, true, window, cx);
11388    }
11389
11390    pub fn duplicate_selection(
11391        &mut self,
11392        _: &DuplicateSelection,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        self.duplicate(false, false, window, cx);
11397    }
11398
11399    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11401        if self.mode.is_single_line() {
11402            cx.propagate();
11403            return;
11404        }
11405
11406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11407        let buffer = self.buffer.read(cx).snapshot(cx);
11408
11409        let mut edits = Vec::new();
11410        let mut unfold_ranges = Vec::new();
11411        let mut refold_creases = Vec::new();
11412
11413        let selections = self.selections.all::<Point>(cx);
11414        let mut selections = selections.iter().peekable();
11415        let mut contiguous_row_selections = Vec::new();
11416        let mut new_selections = Vec::new();
11417
11418        while let Some(selection) = selections.next() {
11419            // Find all the selections that span a contiguous row range
11420            let (start_row, end_row) = consume_contiguous_rows(
11421                &mut contiguous_row_selections,
11422                selection,
11423                &display_map,
11424                &mut selections,
11425            );
11426
11427            // Move the text spanned by the row range to be before the line preceding the row range
11428            if start_row.0 > 0 {
11429                let range_to_move = Point::new(
11430                    start_row.previous_row().0,
11431                    buffer.line_len(start_row.previous_row()),
11432                )
11433                    ..Point::new(
11434                        end_row.previous_row().0,
11435                        buffer.line_len(end_row.previous_row()),
11436                    );
11437                let insertion_point = display_map
11438                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11439                    .0;
11440
11441                // Don't move lines across excerpts
11442                if buffer
11443                    .excerpt_containing(insertion_point..range_to_move.end)
11444                    .is_some()
11445                {
11446                    let text = buffer
11447                        .text_for_range(range_to_move.clone())
11448                        .flat_map(|s| s.chars())
11449                        .skip(1)
11450                        .chain(['\n'])
11451                        .collect::<String>();
11452
11453                    edits.push((
11454                        buffer.anchor_after(range_to_move.start)
11455                            ..buffer.anchor_before(range_to_move.end),
11456                        String::new(),
11457                    ));
11458                    let insertion_anchor = buffer.anchor_after(insertion_point);
11459                    edits.push((insertion_anchor..insertion_anchor, text));
11460
11461                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11462
11463                    // Move selections up
11464                    new_selections.extend(contiguous_row_selections.drain(..).map(
11465                        |mut selection| {
11466                            selection.start.row -= row_delta;
11467                            selection.end.row -= row_delta;
11468                            selection
11469                        },
11470                    ));
11471
11472                    // Move folds up
11473                    unfold_ranges.push(range_to_move.clone());
11474                    for fold in display_map.folds_in_range(
11475                        buffer.anchor_before(range_to_move.start)
11476                            ..buffer.anchor_after(range_to_move.end),
11477                    ) {
11478                        let mut start = fold.range.start.to_point(&buffer);
11479                        let mut end = fold.range.end.to_point(&buffer);
11480                        start.row -= row_delta;
11481                        end.row -= row_delta;
11482                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11483                    }
11484                }
11485            }
11486
11487            // If we didn't move line(s), preserve the existing selections
11488            new_selections.append(&mut contiguous_row_selections);
11489        }
11490
11491        self.transact(window, cx, |this, window, cx| {
11492            this.unfold_ranges(&unfold_ranges, true, true, cx);
11493            this.buffer.update(cx, |buffer, cx| {
11494                for (range, text) in edits {
11495                    buffer.edit([(range, text)], None, cx);
11496                }
11497            });
11498            this.fold_creases(refold_creases, true, window, cx);
11499            this.change_selections(Default::default(), window, cx, |s| {
11500                s.select(new_selections);
11501            })
11502        });
11503    }
11504
11505    pub fn move_line_down(
11506        &mut self,
11507        _: &MoveLineDown,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11512        if self.mode.is_single_line() {
11513            cx.propagate();
11514            return;
11515        }
11516
11517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11518        let buffer = self.buffer.read(cx).snapshot(cx);
11519
11520        let mut edits = Vec::new();
11521        let mut unfold_ranges = Vec::new();
11522        let mut refold_creases = Vec::new();
11523
11524        let selections = self.selections.all::<Point>(cx);
11525        let mut selections = selections.iter().peekable();
11526        let mut contiguous_row_selections = Vec::new();
11527        let mut new_selections = Vec::new();
11528
11529        while let Some(selection) = selections.next() {
11530            // Find all the selections that span a contiguous row range
11531            let (start_row, end_row) = consume_contiguous_rows(
11532                &mut contiguous_row_selections,
11533                selection,
11534                &display_map,
11535                &mut selections,
11536            );
11537
11538            // Move the text spanned by the row range to be after the last line of the row range
11539            if end_row.0 <= buffer.max_point().row {
11540                let range_to_move =
11541                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11542                let insertion_point = display_map
11543                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11544                    .0;
11545
11546                // Don't move lines across excerpt boundaries
11547                if buffer
11548                    .excerpt_containing(range_to_move.start..insertion_point)
11549                    .is_some()
11550                {
11551                    let mut text = String::from("\n");
11552                    text.extend(buffer.text_for_range(range_to_move.clone()));
11553                    text.pop(); // Drop trailing newline
11554                    edits.push((
11555                        buffer.anchor_after(range_to_move.start)
11556                            ..buffer.anchor_before(range_to_move.end),
11557                        String::new(),
11558                    ));
11559                    let insertion_anchor = buffer.anchor_after(insertion_point);
11560                    edits.push((insertion_anchor..insertion_anchor, text));
11561
11562                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11563
11564                    // Move selections down
11565                    new_selections.extend(contiguous_row_selections.drain(..).map(
11566                        |mut selection| {
11567                            selection.start.row += row_delta;
11568                            selection.end.row += row_delta;
11569                            selection
11570                        },
11571                    ));
11572
11573                    // Move folds down
11574                    unfold_ranges.push(range_to_move.clone());
11575                    for fold in display_map.folds_in_range(
11576                        buffer.anchor_before(range_to_move.start)
11577                            ..buffer.anchor_after(range_to_move.end),
11578                    ) {
11579                        let mut start = fold.range.start.to_point(&buffer);
11580                        let mut end = fold.range.end.to_point(&buffer);
11581                        start.row += row_delta;
11582                        end.row += row_delta;
11583                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11584                    }
11585                }
11586            }
11587
11588            // If we didn't move line(s), preserve the existing selections
11589            new_selections.append(&mut contiguous_row_selections);
11590        }
11591
11592        self.transact(window, cx, |this, window, cx| {
11593            this.unfold_ranges(&unfold_ranges, true, true, cx);
11594            this.buffer.update(cx, |buffer, cx| {
11595                for (range, text) in edits {
11596                    buffer.edit([(range, text)], None, cx);
11597                }
11598            });
11599            this.fold_creases(refold_creases, true, window, cx);
11600            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11601        });
11602    }
11603
11604    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11606        let text_layout_details = &self.text_layout_details(window);
11607        self.transact(window, cx, |this, window, cx| {
11608            let edits = this.change_selections(Default::default(), window, cx, |s| {
11609                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11610                s.move_with(|display_map, selection| {
11611                    if !selection.is_empty() {
11612                        return;
11613                    }
11614
11615                    let mut head = selection.head();
11616                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11617                    if head.column() == display_map.line_len(head.row()) {
11618                        transpose_offset = display_map
11619                            .buffer_snapshot
11620                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11621                    }
11622
11623                    if transpose_offset == 0 {
11624                        return;
11625                    }
11626
11627                    *head.column_mut() += 1;
11628                    head = display_map.clip_point(head, Bias::Right);
11629                    let goal = SelectionGoal::HorizontalPosition(
11630                        display_map
11631                            .x_for_display_point(head, text_layout_details)
11632                            .into(),
11633                    );
11634                    selection.collapse_to(head, goal);
11635
11636                    let transpose_start = display_map
11637                        .buffer_snapshot
11638                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11639                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11640                        let transpose_end = display_map
11641                            .buffer_snapshot
11642                            .clip_offset(transpose_offset + 1, Bias::Right);
11643                        if let Some(ch) =
11644                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11645                        {
11646                            edits.push((transpose_start..transpose_offset, String::new()));
11647                            edits.push((transpose_end..transpose_end, ch.to_string()));
11648                        }
11649                    }
11650                });
11651                edits
11652            });
11653            this.buffer
11654                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11655            let selections = this.selections.all::<usize>(cx);
11656            this.change_selections(Default::default(), window, cx, |s| {
11657                s.select(selections);
11658            });
11659        });
11660    }
11661
11662    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11664        if self.mode.is_single_line() {
11665            cx.propagate();
11666            return;
11667        }
11668
11669        self.rewrap_impl(RewrapOptions::default(), cx)
11670    }
11671
11672    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11673        let buffer = self.buffer.read(cx).snapshot(cx);
11674        let selections = self.selections.all::<Point>(cx);
11675
11676        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11677        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11678            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11679                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11680                .peekable();
11681
11682            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11683                row
11684            } else {
11685                return Vec::new();
11686            };
11687
11688            let language_settings = buffer.language_settings_at(selection.head(), cx);
11689            let language_scope = buffer.language_scope_at(selection.head());
11690
11691            let indent_and_prefix_for_row =
11692                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11693                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11694                    let (comment_prefix, rewrap_prefix) =
11695                        if let Some(language_scope) = &language_scope {
11696                            let indent_end = Point::new(row, indent.len);
11697                            let comment_prefix = language_scope
11698                                .line_comment_prefixes()
11699                                .iter()
11700                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11701                                .map(|prefix| prefix.to_string());
11702                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11703                            let line_text_after_indent = buffer
11704                                .text_for_range(indent_end..line_end)
11705                                .collect::<String>();
11706                            let rewrap_prefix = language_scope
11707                                .rewrap_prefixes()
11708                                .iter()
11709                                .find_map(|prefix_regex| {
11710                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11711                                        if mat.start() == 0 {
11712                                            Some(mat.as_str().to_string())
11713                                        } else {
11714                                            None
11715                                        }
11716                                    })
11717                                })
11718                                .flatten();
11719                            (comment_prefix, rewrap_prefix)
11720                        } else {
11721                            (None, None)
11722                        };
11723                    (indent, comment_prefix, rewrap_prefix)
11724                };
11725
11726            let mut ranges = Vec::new();
11727            let from_empty_selection = selection.is_empty();
11728
11729            let mut current_range_start = first_row;
11730            let mut prev_row = first_row;
11731            let (
11732                mut current_range_indent,
11733                mut current_range_comment_prefix,
11734                mut current_range_rewrap_prefix,
11735            ) = indent_and_prefix_for_row(first_row);
11736
11737            for row in non_blank_rows_iter.skip(1) {
11738                let has_paragraph_break = row > prev_row + 1;
11739
11740                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11741                    indent_and_prefix_for_row(row);
11742
11743                let has_indent_change = row_indent != current_range_indent;
11744                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11745
11746                let has_boundary_change = has_comment_change
11747                    || row_rewrap_prefix.is_some()
11748                    || (has_indent_change && current_range_comment_prefix.is_some());
11749
11750                if has_paragraph_break || has_boundary_change {
11751                    ranges.push((
11752                        language_settings.clone(),
11753                        Point::new(current_range_start, 0)
11754                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11755                        current_range_indent,
11756                        current_range_comment_prefix.clone(),
11757                        current_range_rewrap_prefix.clone(),
11758                        from_empty_selection,
11759                    ));
11760                    current_range_start = row;
11761                    current_range_indent = row_indent;
11762                    current_range_comment_prefix = row_comment_prefix;
11763                    current_range_rewrap_prefix = row_rewrap_prefix;
11764                }
11765                prev_row = row;
11766            }
11767
11768            ranges.push((
11769                language_settings.clone(),
11770                Point::new(current_range_start, 0)
11771                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11772                current_range_indent,
11773                current_range_comment_prefix,
11774                current_range_rewrap_prefix,
11775                from_empty_selection,
11776            ));
11777
11778            ranges
11779        });
11780
11781        let mut edits = Vec::new();
11782        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11783
11784        for (
11785            language_settings,
11786            wrap_range,
11787            indent_size,
11788            comment_prefix,
11789            rewrap_prefix,
11790            from_empty_selection,
11791        ) in wrap_ranges
11792        {
11793            let mut start_row = wrap_range.start.row;
11794            let mut end_row = wrap_range.end.row;
11795
11796            // Skip selections that overlap with a range that has already been rewrapped.
11797            let selection_range = start_row..end_row;
11798            if rewrapped_row_ranges
11799                .iter()
11800                .any(|range| range.overlaps(&selection_range))
11801            {
11802                continue;
11803            }
11804
11805            let tab_size = language_settings.tab_size;
11806
11807            let indent_prefix = indent_size.chars().collect::<String>();
11808            let mut line_prefix = indent_prefix.clone();
11809            let mut inside_comment = false;
11810            if let Some(prefix) = &comment_prefix {
11811                line_prefix.push_str(prefix);
11812                inside_comment = true;
11813            }
11814            if let Some(prefix) = &rewrap_prefix {
11815                line_prefix.push_str(prefix);
11816            }
11817
11818            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11819                RewrapBehavior::InComments => inside_comment,
11820                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11821                RewrapBehavior::Anywhere => true,
11822            };
11823
11824            let should_rewrap = options.override_language_settings
11825                || allow_rewrap_based_on_language
11826                || self.hard_wrap.is_some();
11827            if !should_rewrap {
11828                continue;
11829            }
11830
11831            if from_empty_selection {
11832                'expand_upwards: while start_row > 0 {
11833                    let prev_row = start_row - 1;
11834                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11835                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11836                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11837                    {
11838                        start_row = prev_row;
11839                    } else {
11840                        break 'expand_upwards;
11841                    }
11842                }
11843
11844                'expand_downwards: while end_row < buffer.max_point().row {
11845                    let next_row = end_row + 1;
11846                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11847                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11848                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11849                    {
11850                        end_row = next_row;
11851                    } else {
11852                        break 'expand_downwards;
11853                    }
11854                }
11855            }
11856
11857            let start = Point::new(start_row, 0);
11858            let start_offset = start.to_offset(&buffer);
11859            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11860            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11861            let Some(lines_without_prefixes) = selection_text
11862                .lines()
11863                .enumerate()
11864                .map(|(ix, line)| {
11865                    let line_trimmed = line.trim_start();
11866                    if rewrap_prefix.is_some() && ix > 0 {
11867                        Ok(line_trimmed)
11868                    } else {
11869                        line_trimmed
11870                            .strip_prefix(&line_prefix.trim_start())
11871                            .with_context(|| {
11872                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11873                            })
11874                    }
11875                })
11876                .collect::<Result<Vec<_>, _>>()
11877                .log_err()
11878            else {
11879                continue;
11880            };
11881
11882            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11883                buffer
11884                    .language_settings_at(Point::new(start_row, 0), cx)
11885                    .preferred_line_length as usize
11886            });
11887
11888            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11889                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11890            } else {
11891                line_prefix.clone()
11892            };
11893
11894            let wrapped_text = wrap_with_prefix(
11895                line_prefix,
11896                subsequent_lines_prefix,
11897                lines_without_prefixes.join("\n"),
11898                wrap_column,
11899                tab_size,
11900                options.preserve_existing_whitespace,
11901            );
11902
11903            // TODO: should always use char-based diff while still supporting cursor behavior that
11904            // matches vim.
11905            let mut diff_options = DiffOptions::default();
11906            if options.override_language_settings {
11907                diff_options.max_word_diff_len = 0;
11908                diff_options.max_word_diff_line_count = 0;
11909            } else {
11910                diff_options.max_word_diff_len = usize::MAX;
11911                diff_options.max_word_diff_line_count = usize::MAX;
11912            }
11913
11914            for (old_range, new_text) in
11915                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11916            {
11917                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11918                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11919                edits.push((edit_start..edit_end, new_text));
11920            }
11921
11922            rewrapped_row_ranges.push(start_row..=end_row);
11923        }
11924
11925        self.buffer
11926            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11927    }
11928
11929    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11930        let mut text = String::new();
11931        let buffer = self.buffer.read(cx).snapshot(cx);
11932        let mut selections = self.selections.all::<Point>(cx);
11933        let mut clipboard_selections = Vec::with_capacity(selections.len());
11934        {
11935            let max_point = buffer.max_point();
11936            let mut is_first = true;
11937            for selection in &mut selections {
11938                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11939                if is_entire_line {
11940                    selection.start = Point::new(selection.start.row, 0);
11941                    if !selection.is_empty() && selection.end.column == 0 {
11942                        selection.end = cmp::min(max_point, selection.end);
11943                    } else {
11944                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11945                    }
11946                    selection.goal = SelectionGoal::None;
11947                }
11948                if is_first {
11949                    is_first = false;
11950                } else {
11951                    text += "\n";
11952                }
11953                let mut len = 0;
11954                for chunk in buffer.text_for_range(selection.start..selection.end) {
11955                    text.push_str(chunk);
11956                    len += chunk.len();
11957                }
11958                clipboard_selections.push(ClipboardSelection {
11959                    len,
11960                    is_entire_line,
11961                    first_line_indent: buffer
11962                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11963                        .len,
11964                });
11965            }
11966        }
11967
11968        self.transact(window, cx, |this, window, cx| {
11969            this.change_selections(Default::default(), window, cx, |s| {
11970                s.select(selections);
11971            });
11972            this.insert("", window, cx);
11973        });
11974        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11975    }
11976
11977    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11978        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11979        let item = self.cut_common(window, cx);
11980        cx.write_to_clipboard(item);
11981    }
11982
11983    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11984        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11985        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11986            s.move_with(|snapshot, sel| {
11987                if sel.is_empty() {
11988                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11989                }
11990            });
11991        });
11992        let item = self.cut_common(window, cx);
11993        cx.set_global(KillRing(item))
11994    }
11995
11996    pub fn kill_ring_yank(
11997        &mut self,
11998        _: &KillRingYank,
11999        window: &mut Window,
12000        cx: &mut Context<Self>,
12001    ) {
12002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12003        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12004            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12005                (kill_ring.text().to_string(), kill_ring.metadata_json())
12006            } else {
12007                return;
12008            }
12009        } else {
12010            return;
12011        };
12012        self.do_paste(&text, metadata, false, window, cx);
12013    }
12014
12015    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12016        self.do_copy(true, cx);
12017    }
12018
12019    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12020        self.do_copy(false, cx);
12021    }
12022
12023    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12024        let selections = self.selections.all::<Point>(cx);
12025        let buffer = self.buffer.read(cx).read(cx);
12026        let mut text = String::new();
12027
12028        let mut clipboard_selections = Vec::with_capacity(selections.len());
12029        {
12030            let max_point = buffer.max_point();
12031            let mut is_first = true;
12032            for selection in &selections {
12033                let mut start = selection.start;
12034                let mut end = selection.end;
12035                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12036                if is_entire_line {
12037                    start = Point::new(start.row, 0);
12038                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12039                }
12040
12041                let mut trimmed_selections = Vec::new();
12042                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12043                    let row = MultiBufferRow(start.row);
12044                    let first_indent = buffer.indent_size_for_line(row);
12045                    if first_indent.len == 0 || start.column > first_indent.len {
12046                        trimmed_selections.push(start..end);
12047                    } else {
12048                        trimmed_selections.push(
12049                            Point::new(row.0, first_indent.len)
12050                                ..Point::new(row.0, buffer.line_len(row)),
12051                        );
12052                        for row in start.row + 1..=end.row {
12053                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12054                            if row == end.row {
12055                                line_len = end.column;
12056                            }
12057                            if line_len == 0 {
12058                                trimmed_selections
12059                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12060                                continue;
12061                            }
12062                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12063                            if row_indent_size.len >= first_indent.len {
12064                                trimmed_selections.push(
12065                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12066                                );
12067                            } else {
12068                                trimmed_selections.clear();
12069                                trimmed_selections.push(start..end);
12070                                break;
12071                            }
12072                        }
12073                    }
12074                } else {
12075                    trimmed_selections.push(start..end);
12076                }
12077
12078                for trimmed_range in trimmed_selections {
12079                    if is_first {
12080                        is_first = false;
12081                    } else {
12082                        text += "\n";
12083                    }
12084                    let mut len = 0;
12085                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12086                        text.push_str(chunk);
12087                        len += chunk.len();
12088                    }
12089                    clipboard_selections.push(ClipboardSelection {
12090                        len,
12091                        is_entire_line,
12092                        first_line_indent: buffer
12093                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12094                            .len,
12095                    });
12096                }
12097            }
12098        }
12099
12100        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12101            text,
12102            clipboard_selections,
12103        ));
12104    }
12105
12106    pub fn do_paste(
12107        &mut self,
12108        text: &String,
12109        clipboard_selections: Option<Vec<ClipboardSelection>>,
12110        handle_entire_lines: bool,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        if self.read_only(cx) {
12115            return;
12116        }
12117
12118        let clipboard_text = Cow::Borrowed(text);
12119
12120        self.transact(window, cx, |this, window, cx| {
12121            if let Some(mut clipboard_selections) = clipboard_selections {
12122                let old_selections = this.selections.all::<usize>(cx);
12123                let all_selections_were_entire_line =
12124                    clipboard_selections.iter().all(|s| s.is_entire_line);
12125                let first_selection_indent_column =
12126                    clipboard_selections.first().map(|s| s.first_line_indent);
12127                if clipboard_selections.len() != old_selections.len() {
12128                    clipboard_selections.drain(..);
12129                }
12130                let cursor_offset = this.selections.last::<usize>(cx).head();
12131                let mut auto_indent_on_paste = true;
12132
12133                this.buffer.update(cx, |buffer, cx| {
12134                    let snapshot = buffer.read(cx);
12135                    auto_indent_on_paste = snapshot
12136                        .language_settings_at(cursor_offset, cx)
12137                        .auto_indent_on_paste;
12138
12139                    let mut start_offset = 0;
12140                    let mut edits = Vec::new();
12141                    let mut original_indent_columns = Vec::new();
12142                    for (ix, selection) in old_selections.iter().enumerate() {
12143                        let to_insert;
12144                        let entire_line;
12145                        let original_indent_column;
12146                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12147                            let end_offset = start_offset + clipboard_selection.len;
12148                            to_insert = &clipboard_text[start_offset..end_offset];
12149                            entire_line = clipboard_selection.is_entire_line;
12150                            start_offset = end_offset + 1;
12151                            original_indent_column = Some(clipboard_selection.first_line_indent);
12152                        } else {
12153                            to_insert = clipboard_text.as_str();
12154                            entire_line = all_selections_were_entire_line;
12155                            original_indent_column = first_selection_indent_column
12156                        }
12157
12158                        // If the corresponding selection was empty when this slice of the
12159                        // clipboard text was written, then the entire line containing the
12160                        // selection was copied. If this selection is also currently empty,
12161                        // then paste the line before the current line of the buffer.
12162                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12163                            let column = selection.start.to_point(&snapshot).column as usize;
12164                            let line_start = selection.start - column;
12165                            line_start..line_start
12166                        } else {
12167                            selection.range()
12168                        };
12169
12170                        edits.push((range, to_insert));
12171                        original_indent_columns.push(original_indent_column);
12172                    }
12173                    drop(snapshot);
12174
12175                    buffer.edit(
12176                        edits,
12177                        if auto_indent_on_paste {
12178                            Some(AutoindentMode::Block {
12179                                original_indent_columns,
12180                            })
12181                        } else {
12182                            None
12183                        },
12184                        cx,
12185                    );
12186                });
12187
12188                let selections = this.selections.all::<usize>(cx);
12189                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12190            } else {
12191                this.insert(&clipboard_text, window, cx);
12192            }
12193        });
12194    }
12195
12196    pub fn diff_clipboard_with_selection(
12197        &mut self,
12198        _: &DiffClipboardWithSelection,
12199        window: &mut Window,
12200        cx: &mut Context<Self>,
12201    ) {
12202        let selections = self.selections.all::<usize>(cx);
12203
12204        if selections.is_empty() {
12205            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12206            return;
12207        };
12208
12209        let clipboard_text = match cx.read_from_clipboard() {
12210            Some(item) => match item.entries().first() {
12211                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12212                _ => None,
12213            },
12214            None => None,
12215        };
12216
12217        let Some(clipboard_text) = clipboard_text else {
12218            log::warn!("Clipboard doesn't contain text.");
12219            return;
12220        };
12221
12222        window.dispatch_action(
12223            Box::new(DiffClipboardWithSelectionData {
12224                clipboard_text,
12225                editor: cx.entity(),
12226            }),
12227            cx,
12228        );
12229    }
12230
12231    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12233        if let Some(item) = cx.read_from_clipboard() {
12234            let entries = item.entries();
12235
12236            match entries.first() {
12237                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12238                // of all the pasted entries.
12239                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12240                    .do_paste(
12241                        clipboard_string.text(),
12242                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12243                        true,
12244                        window,
12245                        cx,
12246                    ),
12247                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12248            }
12249        }
12250    }
12251
12252    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12253        if self.read_only(cx) {
12254            return;
12255        }
12256
12257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12258
12259        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12260            if let Some((selections, _)) =
12261                self.selection_history.transaction(transaction_id).cloned()
12262            {
12263                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12264                    s.select_anchors(selections.to_vec());
12265                });
12266            } else {
12267                log::error!(
12268                    "No entry in selection_history found for undo. \
12269                     This may correspond to a bug where undo does not update the selection. \
12270                     If this is occurring, please add details to \
12271                     https://github.com/zed-industries/zed/issues/22692"
12272                );
12273            }
12274            self.request_autoscroll(Autoscroll::fit(), cx);
12275            self.unmark_text(window, cx);
12276            self.refresh_inline_completion(true, false, window, cx);
12277            cx.emit(EditorEvent::Edited { transaction_id });
12278            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12279        }
12280    }
12281
12282    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12283        if self.read_only(cx) {
12284            return;
12285        }
12286
12287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12288
12289        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12290            if let Some((_, Some(selections))) =
12291                self.selection_history.transaction(transaction_id).cloned()
12292            {
12293                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12294                    s.select_anchors(selections.to_vec());
12295                });
12296            } else {
12297                log::error!(
12298                    "No entry in selection_history found for redo. \
12299                     This may correspond to a bug where undo does not update the selection. \
12300                     If this is occurring, please add details to \
12301                     https://github.com/zed-industries/zed/issues/22692"
12302                );
12303            }
12304            self.request_autoscroll(Autoscroll::fit(), cx);
12305            self.unmark_text(window, cx);
12306            self.refresh_inline_completion(true, false, window, cx);
12307            cx.emit(EditorEvent::Edited { transaction_id });
12308        }
12309    }
12310
12311    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12312        self.buffer
12313            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12314    }
12315
12316    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12317        self.buffer
12318            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12319    }
12320
12321    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12323        self.change_selections(Default::default(), window, cx, |s| {
12324            s.move_with(|map, selection| {
12325                let cursor = if selection.is_empty() {
12326                    movement::left(map, selection.start)
12327                } else {
12328                    selection.start
12329                };
12330                selection.collapse_to(cursor, SelectionGoal::None);
12331            });
12332        })
12333    }
12334
12335    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12337        self.change_selections(Default::default(), window, cx, |s| {
12338            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12339        })
12340    }
12341
12342    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12344        self.change_selections(Default::default(), window, cx, |s| {
12345            s.move_with(|map, selection| {
12346                let cursor = if selection.is_empty() {
12347                    movement::right(map, selection.end)
12348                } else {
12349                    selection.end
12350                };
12351                selection.collapse_to(cursor, SelectionGoal::None)
12352            });
12353        })
12354    }
12355
12356    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12358        self.change_selections(Default::default(), window, cx, |s| {
12359            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12360        })
12361    }
12362
12363    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12364        if self.take_rename(true, window, cx).is_some() {
12365            return;
12366        }
12367
12368        if self.mode.is_single_line() {
12369            cx.propagate();
12370            return;
12371        }
12372
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12374
12375        let text_layout_details = &self.text_layout_details(window);
12376        let selection_count = self.selections.count();
12377        let first_selection = self.selections.first_anchor();
12378
12379        self.change_selections(Default::default(), window, cx, |s| {
12380            s.move_with(|map, selection| {
12381                if !selection.is_empty() {
12382                    selection.goal = SelectionGoal::None;
12383                }
12384                let (cursor, goal) = movement::up(
12385                    map,
12386                    selection.start,
12387                    selection.goal,
12388                    false,
12389                    text_layout_details,
12390                );
12391                selection.collapse_to(cursor, goal);
12392            });
12393        });
12394
12395        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12396        {
12397            cx.propagate();
12398        }
12399    }
12400
12401    pub fn move_up_by_lines(
12402        &mut self,
12403        action: &MoveUpByLines,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if self.take_rename(true, window, cx).is_some() {
12408            return;
12409        }
12410
12411        if self.mode.is_single_line() {
12412            cx.propagate();
12413            return;
12414        }
12415
12416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12417
12418        let text_layout_details = &self.text_layout_details(window);
12419
12420        self.change_selections(Default::default(), window, cx, |s| {
12421            s.move_with(|map, selection| {
12422                if !selection.is_empty() {
12423                    selection.goal = SelectionGoal::None;
12424                }
12425                let (cursor, goal) = movement::up_by_rows(
12426                    map,
12427                    selection.start,
12428                    action.lines,
12429                    selection.goal,
12430                    false,
12431                    text_layout_details,
12432                );
12433                selection.collapse_to(cursor, goal);
12434            });
12435        })
12436    }
12437
12438    pub fn move_down_by_lines(
12439        &mut self,
12440        action: &MoveDownByLines,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) {
12444        if self.take_rename(true, window, cx).is_some() {
12445            return;
12446        }
12447
12448        if self.mode.is_single_line() {
12449            cx.propagate();
12450            return;
12451        }
12452
12453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12454
12455        let text_layout_details = &self.text_layout_details(window);
12456
12457        self.change_selections(Default::default(), window, cx, |s| {
12458            s.move_with(|map, selection| {
12459                if !selection.is_empty() {
12460                    selection.goal = SelectionGoal::None;
12461                }
12462                let (cursor, goal) = movement::down_by_rows(
12463                    map,
12464                    selection.start,
12465                    action.lines,
12466                    selection.goal,
12467                    false,
12468                    text_layout_details,
12469                );
12470                selection.collapse_to(cursor, goal);
12471            });
12472        })
12473    }
12474
12475    pub fn select_down_by_lines(
12476        &mut self,
12477        action: &SelectDownByLines,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12482        let text_layout_details = &self.text_layout_details(window);
12483        self.change_selections(Default::default(), window, cx, |s| {
12484            s.move_heads_with(|map, head, goal| {
12485                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12486            })
12487        })
12488    }
12489
12490    pub fn select_up_by_lines(
12491        &mut self,
12492        action: &SelectUpByLines,
12493        window: &mut Window,
12494        cx: &mut Context<Self>,
12495    ) {
12496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12497        let text_layout_details = &self.text_layout_details(window);
12498        self.change_selections(Default::default(), window, cx, |s| {
12499            s.move_heads_with(|map, head, goal| {
12500                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12501            })
12502        })
12503    }
12504
12505    pub fn select_page_up(
12506        &mut self,
12507        _: &SelectPageUp,
12508        window: &mut Window,
12509        cx: &mut Context<Self>,
12510    ) {
12511        let Some(row_count) = self.visible_row_count() else {
12512            return;
12513        };
12514
12515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12516
12517        let text_layout_details = &self.text_layout_details(window);
12518
12519        self.change_selections(Default::default(), window, cx, |s| {
12520            s.move_heads_with(|map, head, goal| {
12521                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12522            })
12523        })
12524    }
12525
12526    pub fn move_page_up(
12527        &mut self,
12528        action: &MovePageUp,
12529        window: &mut Window,
12530        cx: &mut Context<Self>,
12531    ) {
12532        if self.take_rename(true, window, cx).is_some() {
12533            return;
12534        }
12535
12536        if self
12537            .context_menu
12538            .borrow_mut()
12539            .as_mut()
12540            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12541            .unwrap_or(false)
12542        {
12543            return;
12544        }
12545
12546        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12547            cx.propagate();
12548            return;
12549        }
12550
12551        let Some(row_count) = self.visible_row_count() else {
12552            return;
12553        };
12554
12555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12556
12557        let effects = if action.center_cursor {
12558            SelectionEffects::scroll(Autoscroll::center())
12559        } else {
12560            SelectionEffects::default()
12561        };
12562
12563        let text_layout_details = &self.text_layout_details(window);
12564
12565        self.change_selections(effects, window, cx, |s| {
12566            s.move_with(|map, selection| {
12567                if !selection.is_empty() {
12568                    selection.goal = SelectionGoal::None;
12569                }
12570                let (cursor, goal) = movement::up_by_rows(
12571                    map,
12572                    selection.end,
12573                    row_count,
12574                    selection.goal,
12575                    false,
12576                    text_layout_details,
12577                );
12578                selection.collapse_to(cursor, goal);
12579            });
12580        });
12581    }
12582
12583    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12585        let text_layout_details = &self.text_layout_details(window);
12586        self.change_selections(Default::default(), window, cx, |s| {
12587            s.move_heads_with(|map, head, goal| {
12588                movement::up(map, head, goal, false, text_layout_details)
12589            })
12590        })
12591    }
12592
12593    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12594        self.take_rename(true, window, cx);
12595
12596        if self.mode.is_single_line() {
12597            cx.propagate();
12598            return;
12599        }
12600
12601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12602
12603        let text_layout_details = &self.text_layout_details(window);
12604        let selection_count = self.selections.count();
12605        let first_selection = self.selections.first_anchor();
12606
12607        self.change_selections(Default::default(), window, cx, |s| {
12608            s.move_with(|map, selection| {
12609                if !selection.is_empty() {
12610                    selection.goal = SelectionGoal::None;
12611                }
12612                let (cursor, goal) = movement::down(
12613                    map,
12614                    selection.end,
12615                    selection.goal,
12616                    false,
12617                    text_layout_details,
12618                );
12619                selection.collapse_to(cursor, goal);
12620            });
12621        });
12622
12623        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12624        {
12625            cx.propagate();
12626        }
12627    }
12628
12629    pub fn select_page_down(
12630        &mut self,
12631        _: &SelectPageDown,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        let Some(row_count) = self.visible_row_count() else {
12636            return;
12637        };
12638
12639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12640
12641        let text_layout_details = &self.text_layout_details(window);
12642
12643        self.change_selections(Default::default(), window, cx, |s| {
12644            s.move_heads_with(|map, head, goal| {
12645                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12646            })
12647        })
12648    }
12649
12650    pub fn move_page_down(
12651        &mut self,
12652        action: &MovePageDown,
12653        window: &mut Window,
12654        cx: &mut Context<Self>,
12655    ) {
12656        if self.take_rename(true, window, cx).is_some() {
12657            return;
12658        }
12659
12660        if self
12661            .context_menu
12662            .borrow_mut()
12663            .as_mut()
12664            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12665            .unwrap_or(false)
12666        {
12667            return;
12668        }
12669
12670        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12671            cx.propagate();
12672            return;
12673        }
12674
12675        let Some(row_count) = self.visible_row_count() else {
12676            return;
12677        };
12678
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680
12681        let effects = if action.center_cursor {
12682            SelectionEffects::scroll(Autoscroll::center())
12683        } else {
12684            SelectionEffects::default()
12685        };
12686
12687        let text_layout_details = &self.text_layout_details(window);
12688        self.change_selections(effects, window, cx, |s| {
12689            s.move_with(|map, selection| {
12690                if !selection.is_empty() {
12691                    selection.goal = SelectionGoal::None;
12692                }
12693                let (cursor, goal) = movement::down_by_rows(
12694                    map,
12695                    selection.end,
12696                    row_count,
12697                    selection.goal,
12698                    false,
12699                    text_layout_details,
12700                );
12701                selection.collapse_to(cursor, goal);
12702            });
12703        });
12704    }
12705
12706    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12708        let text_layout_details = &self.text_layout_details(window);
12709        self.change_selections(Default::default(), window, cx, |s| {
12710            s.move_heads_with(|map, head, goal| {
12711                movement::down(map, head, goal, false, text_layout_details)
12712            })
12713        });
12714    }
12715
12716    pub fn context_menu_first(
12717        &mut self,
12718        _: &ContextMenuFirst,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12723            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12724        }
12725    }
12726
12727    pub fn context_menu_prev(
12728        &mut self,
12729        _: &ContextMenuPrevious,
12730        window: &mut Window,
12731        cx: &mut Context<Self>,
12732    ) {
12733        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12734            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12735        }
12736    }
12737
12738    pub fn context_menu_next(
12739        &mut self,
12740        _: &ContextMenuNext,
12741        window: &mut Window,
12742        cx: &mut Context<Self>,
12743    ) {
12744        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12745            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12746        }
12747    }
12748
12749    pub fn context_menu_last(
12750        &mut self,
12751        _: &ContextMenuLast,
12752        window: &mut Window,
12753        cx: &mut Context<Self>,
12754    ) {
12755        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12756            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12757        }
12758    }
12759
12760    pub fn signature_help_prev(
12761        &mut self,
12762        _: &SignatureHelpPrevious,
12763        _: &mut Window,
12764        cx: &mut Context<Self>,
12765    ) {
12766        if let Some(popover) = self.signature_help_state.popover_mut() {
12767            if popover.current_signature == 0 {
12768                popover.current_signature = popover.signatures.len() - 1;
12769            } else {
12770                popover.current_signature -= 1;
12771            }
12772            cx.notify();
12773        }
12774    }
12775
12776    pub fn signature_help_next(
12777        &mut self,
12778        _: &SignatureHelpNext,
12779        _: &mut Window,
12780        cx: &mut Context<Self>,
12781    ) {
12782        if let Some(popover) = self.signature_help_state.popover_mut() {
12783            if popover.current_signature + 1 == popover.signatures.len() {
12784                popover.current_signature = 0;
12785            } else {
12786                popover.current_signature += 1;
12787            }
12788            cx.notify();
12789        }
12790    }
12791
12792    pub fn move_to_previous_word_start(
12793        &mut self,
12794        _: &MoveToPreviousWordStart,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_cursors_with(|map, head, _| {
12801                (
12802                    movement::previous_word_start(map, head),
12803                    SelectionGoal::None,
12804                )
12805            });
12806        })
12807    }
12808
12809    pub fn move_to_previous_subword_start(
12810        &mut self,
12811        _: &MoveToPreviousSubwordStart,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12816        self.change_selections(Default::default(), window, cx, |s| {
12817            s.move_cursors_with(|map, head, _| {
12818                (
12819                    movement::previous_subword_start(map, head),
12820                    SelectionGoal::None,
12821                )
12822            });
12823        })
12824    }
12825
12826    pub fn select_to_previous_word_start(
12827        &mut self,
12828        _: &SelectToPreviousWordStart,
12829        window: &mut Window,
12830        cx: &mut Context<Self>,
12831    ) {
12832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12833        self.change_selections(Default::default(), window, cx, |s| {
12834            s.move_heads_with(|map, head, _| {
12835                (
12836                    movement::previous_word_start(map, head),
12837                    SelectionGoal::None,
12838                )
12839            });
12840        })
12841    }
12842
12843    pub fn select_to_previous_subword_start(
12844        &mut self,
12845        _: &SelectToPreviousSubwordStart,
12846        window: &mut Window,
12847        cx: &mut Context<Self>,
12848    ) {
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12850        self.change_selections(Default::default(), window, cx, |s| {
12851            s.move_heads_with(|map, head, _| {
12852                (
12853                    movement::previous_subword_start(map, head),
12854                    SelectionGoal::None,
12855                )
12856            });
12857        })
12858    }
12859
12860    pub fn delete_to_previous_word_start(
12861        &mut self,
12862        action: &DeleteToPreviousWordStart,
12863        window: &mut Window,
12864        cx: &mut Context<Self>,
12865    ) {
12866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12867        self.transact(window, cx, |this, window, cx| {
12868            this.select_autoclose_pair(window, cx);
12869            this.change_selections(Default::default(), window, cx, |s| {
12870                s.move_with(|map, selection| {
12871                    if selection.is_empty() {
12872                        let cursor = if action.ignore_newlines {
12873                            movement::previous_word_start(map, selection.head())
12874                        } else {
12875                            movement::previous_word_start_or_newline(map, selection.head())
12876                        };
12877                        selection.set_head(cursor, SelectionGoal::None);
12878                    }
12879                });
12880            });
12881            this.insert("", window, cx);
12882        });
12883    }
12884
12885    pub fn delete_to_previous_subword_start(
12886        &mut self,
12887        _: &DeleteToPreviousSubwordStart,
12888        window: &mut Window,
12889        cx: &mut Context<Self>,
12890    ) {
12891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12892        self.transact(window, cx, |this, window, cx| {
12893            this.select_autoclose_pair(window, cx);
12894            this.change_selections(Default::default(), window, cx, |s| {
12895                s.move_with(|map, selection| {
12896                    if selection.is_empty() {
12897                        let cursor = movement::previous_subword_start(map, selection.head());
12898                        selection.set_head(cursor, SelectionGoal::None);
12899                    }
12900                });
12901            });
12902            this.insert("", window, cx);
12903        });
12904    }
12905
12906    pub fn move_to_next_word_end(
12907        &mut self,
12908        _: &MoveToNextWordEnd,
12909        window: &mut Window,
12910        cx: &mut Context<Self>,
12911    ) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_cursors_with(|map, head, _| {
12915                (movement::next_word_end(map, head), SelectionGoal::None)
12916            });
12917        })
12918    }
12919
12920    pub fn move_to_next_subword_end(
12921        &mut self,
12922        _: &MoveToNextSubwordEnd,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_cursors_with(|map, head, _| {
12929                (movement::next_subword_end(map, head), SelectionGoal::None)
12930            });
12931        })
12932    }
12933
12934    pub fn select_to_next_word_end(
12935        &mut self,
12936        _: &SelectToNextWordEnd,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941        self.change_selections(Default::default(), window, cx, |s| {
12942            s.move_heads_with(|map, head, _| {
12943                (movement::next_word_end(map, head), SelectionGoal::None)
12944            });
12945        })
12946    }
12947
12948    pub fn select_to_next_subword_end(
12949        &mut self,
12950        _: &SelectToNextSubwordEnd,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955        self.change_selections(Default::default(), window, cx, |s| {
12956            s.move_heads_with(|map, head, _| {
12957                (movement::next_subword_end(map, head), SelectionGoal::None)
12958            });
12959        })
12960    }
12961
12962    pub fn delete_to_next_word_end(
12963        &mut self,
12964        action: &DeleteToNextWordEnd,
12965        window: &mut Window,
12966        cx: &mut Context<Self>,
12967    ) {
12968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12969        self.transact(window, cx, |this, window, cx| {
12970            this.change_selections(Default::default(), window, cx, |s| {
12971                s.move_with(|map, selection| {
12972                    if selection.is_empty() {
12973                        let cursor = if action.ignore_newlines {
12974                            movement::next_word_end(map, selection.head())
12975                        } else {
12976                            movement::next_word_end_or_newline(map, selection.head())
12977                        };
12978                        selection.set_head(cursor, SelectionGoal::None);
12979                    }
12980                });
12981            });
12982            this.insert("", window, cx);
12983        });
12984    }
12985
12986    pub fn delete_to_next_subword_end(
12987        &mut self,
12988        _: &DeleteToNextSubwordEnd,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12993        self.transact(window, cx, |this, window, cx| {
12994            this.change_selections(Default::default(), window, cx, |s| {
12995                s.move_with(|map, selection| {
12996                    if selection.is_empty() {
12997                        let cursor = movement::next_subword_end(map, selection.head());
12998                        selection.set_head(cursor, SelectionGoal::None);
12999                    }
13000                });
13001            });
13002            this.insert("", window, cx);
13003        });
13004    }
13005
13006    pub fn move_to_beginning_of_line(
13007        &mut self,
13008        action: &MoveToBeginningOfLine,
13009        window: &mut Window,
13010        cx: &mut Context<Self>,
13011    ) {
13012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13013        self.change_selections(Default::default(), window, cx, |s| {
13014            s.move_cursors_with(|map, head, _| {
13015                (
13016                    movement::indented_line_beginning(
13017                        map,
13018                        head,
13019                        action.stop_at_soft_wraps,
13020                        action.stop_at_indent,
13021                    ),
13022                    SelectionGoal::None,
13023                )
13024            });
13025        })
13026    }
13027
13028    pub fn select_to_beginning_of_line(
13029        &mut self,
13030        action: &SelectToBeginningOfLine,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) {
13034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13035        self.change_selections(Default::default(), window, cx, |s| {
13036            s.move_heads_with(|map, head, _| {
13037                (
13038                    movement::indented_line_beginning(
13039                        map,
13040                        head,
13041                        action.stop_at_soft_wraps,
13042                        action.stop_at_indent,
13043                    ),
13044                    SelectionGoal::None,
13045                )
13046            });
13047        });
13048    }
13049
13050    pub fn delete_to_beginning_of_line(
13051        &mut self,
13052        action: &DeleteToBeginningOfLine,
13053        window: &mut Window,
13054        cx: &mut Context<Self>,
13055    ) {
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13057        self.transact(window, cx, |this, window, cx| {
13058            this.change_selections(Default::default(), window, cx, |s| {
13059                s.move_with(|_, selection| {
13060                    selection.reversed = true;
13061                });
13062            });
13063
13064            this.select_to_beginning_of_line(
13065                &SelectToBeginningOfLine {
13066                    stop_at_soft_wraps: false,
13067                    stop_at_indent: action.stop_at_indent,
13068                },
13069                window,
13070                cx,
13071            );
13072            this.backspace(&Backspace, window, cx);
13073        });
13074    }
13075
13076    pub fn move_to_end_of_line(
13077        &mut self,
13078        action: &MoveToEndOfLine,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) {
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_cursors_with(|map, head, _| {
13085                (
13086                    movement::line_end(map, head, action.stop_at_soft_wraps),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn select_to_end_of_line(
13094        &mut self,
13095        action: &SelectToEndOfLine,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_heads_with(|map, head, _| {
13102                (
13103                    movement::line_end(map, head, action.stop_at_soft_wraps),
13104                    SelectionGoal::None,
13105                )
13106            });
13107        })
13108    }
13109
13110    pub fn delete_to_end_of_line(
13111        &mut self,
13112        _: &DeleteToEndOfLine,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13117        self.transact(window, cx, |this, window, cx| {
13118            this.select_to_end_of_line(
13119                &SelectToEndOfLine {
13120                    stop_at_soft_wraps: false,
13121                },
13122                window,
13123                cx,
13124            );
13125            this.delete(&Delete, window, cx);
13126        });
13127    }
13128
13129    pub fn cut_to_end_of_line(
13130        &mut self,
13131        _: &CutToEndOfLine,
13132        window: &mut Window,
13133        cx: &mut Context<Self>,
13134    ) {
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13136        self.transact(window, cx, |this, window, cx| {
13137            this.select_to_end_of_line(
13138                &SelectToEndOfLine {
13139                    stop_at_soft_wraps: false,
13140                },
13141                window,
13142                cx,
13143            );
13144            this.cut(&Cut, window, cx);
13145        });
13146    }
13147
13148    pub fn move_to_start_of_paragraph(
13149        &mut self,
13150        _: &MoveToStartOfParagraph,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13155            cx.propagate();
13156            return;
13157        }
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159        self.change_selections(Default::default(), window, cx, |s| {
13160            s.move_with(|map, selection| {
13161                selection.collapse_to(
13162                    movement::start_of_paragraph(map, selection.head(), 1),
13163                    SelectionGoal::None,
13164                )
13165            });
13166        })
13167    }
13168
13169    pub fn move_to_end_of_paragraph(
13170        &mut self,
13171        _: &MoveToEndOfParagraph,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13176            cx.propagate();
13177            return;
13178        }
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_with(|map, selection| {
13182                selection.collapse_to(
13183                    movement::end_of_paragraph(map, selection.head(), 1),
13184                    SelectionGoal::None,
13185                )
13186            });
13187        })
13188    }
13189
13190    pub fn select_to_start_of_paragraph(
13191        &mut self,
13192        _: &SelectToStartOfParagraph,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13197            cx.propagate();
13198            return;
13199        }
13200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13201        self.change_selections(Default::default(), window, cx, |s| {
13202            s.move_heads_with(|map, head, _| {
13203                (
13204                    movement::start_of_paragraph(map, head, 1),
13205                    SelectionGoal::None,
13206                )
13207            });
13208        })
13209    }
13210
13211    pub fn select_to_end_of_paragraph(
13212        &mut self,
13213        _: &SelectToEndOfParagraph,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13218            cx.propagate();
13219            return;
13220        }
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222        self.change_selections(Default::default(), window, cx, |s| {
13223            s.move_heads_with(|map, head, _| {
13224                (
13225                    movement::end_of_paragraph(map, head, 1),
13226                    SelectionGoal::None,
13227                )
13228            });
13229        })
13230    }
13231
13232    pub fn move_to_start_of_excerpt(
13233        &mut self,
13234        _: &MoveToStartOfExcerpt,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13239            cx.propagate();
13240            return;
13241        }
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        self.change_selections(Default::default(), window, cx, |s| {
13244            s.move_with(|map, selection| {
13245                selection.collapse_to(
13246                    movement::start_of_excerpt(
13247                        map,
13248                        selection.head(),
13249                        workspace::searchable::Direction::Prev,
13250                    ),
13251                    SelectionGoal::None,
13252                )
13253            });
13254        })
13255    }
13256
13257    pub fn move_to_start_of_next_excerpt(
13258        &mut self,
13259        _: &MoveToStartOfNextExcerpt,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13264            cx.propagate();
13265            return;
13266        }
13267
13268        self.change_selections(Default::default(), window, cx, |s| {
13269            s.move_with(|map, selection| {
13270                selection.collapse_to(
13271                    movement::start_of_excerpt(
13272                        map,
13273                        selection.head(),
13274                        workspace::searchable::Direction::Next,
13275                    ),
13276                    SelectionGoal::None,
13277                )
13278            });
13279        })
13280    }
13281
13282    pub fn move_to_end_of_excerpt(
13283        &mut self,
13284        _: &MoveToEndOfExcerpt,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13289            cx.propagate();
13290            return;
13291        }
13292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.move_with(|map, selection| {
13295                selection.collapse_to(
13296                    movement::end_of_excerpt(
13297                        map,
13298                        selection.head(),
13299                        workspace::searchable::Direction::Next,
13300                    ),
13301                    SelectionGoal::None,
13302                )
13303            });
13304        })
13305    }
13306
13307    pub fn move_to_end_of_previous_excerpt(
13308        &mut self,
13309        _: &MoveToEndOfPreviousExcerpt,
13310        window: &mut Window,
13311        cx: &mut Context<Self>,
13312    ) {
13313        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13314            cx.propagate();
13315            return;
13316        }
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13318        self.change_selections(Default::default(), window, cx, |s| {
13319            s.move_with(|map, selection| {
13320                selection.collapse_to(
13321                    movement::end_of_excerpt(
13322                        map,
13323                        selection.head(),
13324                        workspace::searchable::Direction::Prev,
13325                    ),
13326                    SelectionGoal::None,
13327                )
13328            });
13329        })
13330    }
13331
13332    pub fn select_to_start_of_excerpt(
13333        &mut self,
13334        _: &SelectToStartOfExcerpt,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13339            cx.propagate();
13340            return;
13341        }
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.move_heads_with(|map, head, _| {
13345                (
13346                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13347                    SelectionGoal::None,
13348                )
13349            });
13350        })
13351    }
13352
13353    pub fn select_to_start_of_next_excerpt(
13354        &mut self,
13355        _: &SelectToStartOfNextExcerpt,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13360            cx.propagate();
13361            return;
13362        }
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_heads_with(|map, head, _| {
13366                (
13367                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13368                    SelectionGoal::None,
13369                )
13370            });
13371        })
13372    }
13373
13374    pub fn select_to_end_of_excerpt(
13375        &mut self,
13376        _: &SelectToEndOfExcerpt,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13381            cx.propagate();
13382            return;
13383        }
13384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13385        self.change_selections(Default::default(), window, cx, |s| {
13386            s.move_heads_with(|map, head, _| {
13387                (
13388                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13389                    SelectionGoal::None,
13390                )
13391            });
13392        })
13393    }
13394
13395    pub fn select_to_end_of_previous_excerpt(
13396        &mut self,
13397        _: &SelectToEndOfPreviousExcerpt,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13402            cx.propagate();
13403            return;
13404        }
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_heads_with(|map, head, _| {
13408                (
13409                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn move_to_beginning(
13417        &mut self,
13418        _: &MoveToBeginning,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13423            cx.propagate();
13424            return;
13425        }
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        self.change_selections(Default::default(), window, cx, |s| {
13428            s.select_ranges(vec![0..0]);
13429        });
13430    }
13431
13432    pub fn select_to_beginning(
13433        &mut self,
13434        _: &SelectToBeginning,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        let mut selection = self.selections.last::<Point>(cx);
13439        selection.set_head(Point::zero(), SelectionGoal::None);
13440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.select(vec![selection]);
13443        });
13444    }
13445
13446    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13447        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13448            cx.propagate();
13449            return;
13450        }
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        let cursor = self.buffer.read(cx).read(cx).len();
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.select_ranges(vec![cursor..cursor])
13455        });
13456    }
13457
13458    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13459        self.nav_history = nav_history;
13460    }
13461
13462    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13463        self.nav_history.as_ref()
13464    }
13465
13466    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13467        self.push_to_nav_history(
13468            self.selections.newest_anchor().head(),
13469            None,
13470            false,
13471            true,
13472            cx,
13473        );
13474    }
13475
13476    fn push_to_nav_history(
13477        &mut self,
13478        cursor_anchor: Anchor,
13479        new_position: Option<Point>,
13480        is_deactivate: bool,
13481        always: bool,
13482        cx: &mut Context<Self>,
13483    ) {
13484        if let Some(nav_history) = self.nav_history.as_mut() {
13485            let buffer = self.buffer.read(cx).read(cx);
13486            let cursor_position = cursor_anchor.to_point(&buffer);
13487            let scroll_state = self.scroll_manager.anchor();
13488            let scroll_top_row = scroll_state.top_row(&buffer);
13489            drop(buffer);
13490
13491            if let Some(new_position) = new_position {
13492                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13493                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13494                    return;
13495                }
13496            }
13497
13498            nav_history.push(
13499                Some(NavigationData {
13500                    cursor_anchor,
13501                    cursor_position,
13502                    scroll_anchor: scroll_state,
13503                    scroll_top_row,
13504                }),
13505                cx,
13506            );
13507            cx.emit(EditorEvent::PushedToNavHistory {
13508                anchor: cursor_anchor,
13509                is_deactivate,
13510            })
13511        }
13512    }
13513
13514    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13516        let buffer = self.buffer.read(cx).snapshot(cx);
13517        let mut selection = self.selections.first::<usize>(cx);
13518        selection.set_head(buffer.len(), SelectionGoal::None);
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.select(vec![selection]);
13521        });
13522    }
13523
13524    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13526        let end = self.buffer.read(cx).read(cx).len();
13527        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13528            s.select_ranges(vec![0..end]);
13529        });
13530    }
13531
13532    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13533        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13535        let mut selections = self.selections.all::<Point>(cx);
13536        let max_point = display_map.buffer_snapshot.max_point();
13537        for selection in &mut selections {
13538            let rows = selection.spanned_rows(true, &display_map);
13539            selection.start = Point::new(rows.start.0, 0);
13540            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13541            selection.reversed = false;
13542        }
13543        self.change_selections(Default::default(), window, cx, |s| {
13544            s.select(selections);
13545        });
13546    }
13547
13548    pub fn split_selection_into_lines(
13549        &mut self,
13550        _: &SplitSelectionIntoLines,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) {
13554        let selections = self
13555            .selections
13556            .all::<Point>(cx)
13557            .into_iter()
13558            .map(|selection| selection.start..selection.end)
13559            .collect::<Vec<_>>();
13560        self.unfold_ranges(&selections, true, true, cx);
13561
13562        let mut new_selection_ranges = Vec::new();
13563        {
13564            let buffer = self.buffer.read(cx).read(cx);
13565            for selection in selections {
13566                for row in selection.start.row..selection.end.row {
13567                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13568                    new_selection_ranges.push(cursor..cursor);
13569                }
13570
13571                let is_multiline_selection = selection.start.row != selection.end.row;
13572                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13573                // so this action feels more ergonomic when paired with other selection operations
13574                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13575                if !should_skip_last {
13576                    new_selection_ranges.push(selection.end..selection.end);
13577                }
13578            }
13579        }
13580        self.change_selections(Default::default(), window, cx, |s| {
13581            s.select_ranges(new_selection_ranges);
13582        });
13583    }
13584
13585    pub fn add_selection_above(
13586        &mut self,
13587        _: &AddSelectionAbove,
13588        window: &mut Window,
13589        cx: &mut Context<Self>,
13590    ) {
13591        self.add_selection(true, window, cx);
13592    }
13593
13594    pub fn add_selection_below(
13595        &mut self,
13596        _: &AddSelectionBelow,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.add_selection(false, window, cx);
13601    }
13602
13603    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13605
13606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13607        let all_selections = self.selections.all::<Point>(cx);
13608        let text_layout_details = self.text_layout_details(window);
13609
13610        let (mut columnar_selections, new_selections_to_columnarize) = {
13611            if let Some(state) = self.add_selections_state.as_ref() {
13612                let columnar_selection_ids: HashSet<_> = state
13613                    .groups
13614                    .iter()
13615                    .flat_map(|group| group.stack.iter())
13616                    .copied()
13617                    .collect();
13618
13619                all_selections
13620                    .into_iter()
13621                    .partition(|s| columnar_selection_ids.contains(&s.id))
13622            } else {
13623                (Vec::new(), all_selections)
13624            }
13625        };
13626
13627        let mut state = self
13628            .add_selections_state
13629            .take()
13630            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13631
13632        for selection in new_selections_to_columnarize {
13633            let range = selection.display_range(&display_map).sorted();
13634            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13635            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13636            let positions = start_x.min(end_x)..start_x.max(end_x);
13637            let mut stack = Vec::new();
13638            for row in range.start.row().0..=range.end.row().0 {
13639                if let Some(selection) = self.selections.build_columnar_selection(
13640                    &display_map,
13641                    DisplayRow(row),
13642                    &positions,
13643                    selection.reversed,
13644                    &text_layout_details,
13645                ) {
13646                    stack.push(selection.id);
13647                    columnar_selections.push(selection);
13648                }
13649            }
13650            if !stack.is_empty() {
13651                if above {
13652                    stack.reverse();
13653                }
13654                state.groups.push(AddSelectionsGroup { above, stack });
13655            }
13656        }
13657
13658        let mut final_selections = Vec::new();
13659        let end_row = if above {
13660            DisplayRow(0)
13661        } else {
13662            display_map.max_point().row()
13663        };
13664
13665        let mut last_added_item_per_group = HashMap::default();
13666        for group in state.groups.iter_mut() {
13667            if let Some(last_id) = group.stack.last() {
13668                last_added_item_per_group.insert(*last_id, group);
13669            }
13670        }
13671
13672        for selection in columnar_selections {
13673            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13674                if above == group.above {
13675                    let range = selection.display_range(&display_map).sorted();
13676                    debug_assert_eq!(range.start.row(), range.end.row());
13677                    let mut row = range.start.row();
13678                    let positions =
13679                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13680                            px(start)..px(end)
13681                        } else {
13682                            let start_x =
13683                                display_map.x_for_display_point(range.start, &text_layout_details);
13684                            let end_x =
13685                                display_map.x_for_display_point(range.end, &text_layout_details);
13686                            start_x.min(end_x)..start_x.max(end_x)
13687                        };
13688
13689                    let mut maybe_new_selection = None;
13690                    while row != end_row {
13691                        if above {
13692                            row.0 -= 1;
13693                        } else {
13694                            row.0 += 1;
13695                        }
13696                        if let Some(new_selection) = self.selections.build_columnar_selection(
13697                            &display_map,
13698                            row,
13699                            &positions,
13700                            selection.reversed,
13701                            &text_layout_details,
13702                        ) {
13703                            maybe_new_selection = Some(new_selection);
13704                            break;
13705                        }
13706                    }
13707
13708                    if let Some(new_selection) = maybe_new_selection {
13709                        group.stack.push(new_selection.id);
13710                        if above {
13711                            final_selections.push(new_selection);
13712                            final_selections.push(selection);
13713                        } else {
13714                            final_selections.push(selection);
13715                            final_selections.push(new_selection);
13716                        }
13717                    } else {
13718                        final_selections.push(selection);
13719                    }
13720                } else {
13721                    group.stack.pop();
13722                }
13723            } else {
13724                final_selections.push(selection);
13725            }
13726        }
13727
13728        self.change_selections(Default::default(), window, cx, |s| {
13729            s.select(final_selections);
13730        });
13731
13732        let final_selection_ids: HashSet<_> = self
13733            .selections
13734            .all::<Point>(cx)
13735            .iter()
13736            .map(|s| s.id)
13737            .collect();
13738        state.groups.retain_mut(|group| {
13739            // selections might get merged above so we remove invalid items from stacks
13740            group.stack.retain(|id| final_selection_ids.contains(id));
13741
13742            // single selection in stack can be treated as initial state
13743            group.stack.len() > 1
13744        });
13745
13746        if !state.groups.is_empty() {
13747            self.add_selections_state = Some(state);
13748        }
13749    }
13750
13751    fn select_match_ranges(
13752        &mut self,
13753        range: Range<usize>,
13754        reversed: bool,
13755        replace_newest: bool,
13756        auto_scroll: Option<Autoscroll>,
13757        window: &mut Window,
13758        cx: &mut Context<Editor>,
13759    ) {
13760        self.unfold_ranges(
13761            std::slice::from_ref(&range),
13762            false,
13763            auto_scroll.is_some(),
13764            cx,
13765        );
13766        let effects = if let Some(scroll) = auto_scroll {
13767            SelectionEffects::scroll(scroll)
13768        } else {
13769            SelectionEffects::no_scroll()
13770        };
13771        self.change_selections(effects, window, cx, |s| {
13772            if replace_newest {
13773                s.delete(s.newest_anchor().id);
13774            }
13775            if reversed {
13776                s.insert_range(range.end..range.start);
13777            } else {
13778                s.insert_range(range);
13779            }
13780        });
13781    }
13782
13783    pub fn select_next_match_internal(
13784        &mut self,
13785        display_map: &DisplaySnapshot,
13786        replace_newest: bool,
13787        autoscroll: Option<Autoscroll>,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) -> Result<()> {
13791        let buffer = &display_map.buffer_snapshot;
13792        let mut selections = self.selections.all::<usize>(cx);
13793        if let Some(mut select_next_state) = self.select_next_state.take() {
13794            let query = &select_next_state.query;
13795            if !select_next_state.done {
13796                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13797                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13798                let mut next_selected_range = None;
13799
13800                let bytes_after_last_selection =
13801                    buffer.bytes_in_range(last_selection.end..buffer.len());
13802                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13803                let query_matches = query
13804                    .stream_find_iter(bytes_after_last_selection)
13805                    .map(|result| (last_selection.end, result))
13806                    .chain(
13807                        query
13808                            .stream_find_iter(bytes_before_first_selection)
13809                            .map(|result| (0, result)),
13810                    );
13811
13812                for (start_offset, query_match) in query_matches {
13813                    let query_match = query_match.unwrap(); // can only fail due to I/O
13814                    let offset_range =
13815                        start_offset + query_match.start()..start_offset + query_match.end();
13816
13817                    if !select_next_state.wordwise
13818                        || (!buffer.is_inside_word(offset_range.start, false)
13819                            && !buffer.is_inside_word(offset_range.end, false))
13820                    {
13821                        // TODO: This is n^2, because we might check all the selections
13822                        if !selections
13823                            .iter()
13824                            .any(|selection| selection.range().overlaps(&offset_range))
13825                        {
13826                            next_selected_range = Some(offset_range);
13827                            break;
13828                        }
13829                    }
13830                }
13831
13832                if let Some(next_selected_range) = next_selected_range {
13833                    self.select_match_ranges(
13834                        next_selected_range,
13835                        last_selection.reversed,
13836                        replace_newest,
13837                        autoscroll,
13838                        window,
13839                        cx,
13840                    );
13841                } else {
13842                    select_next_state.done = true;
13843                }
13844            }
13845
13846            self.select_next_state = Some(select_next_state);
13847        } else {
13848            let mut only_carets = true;
13849            let mut same_text_selected = true;
13850            let mut selected_text = None;
13851
13852            let mut selections_iter = selections.iter().peekable();
13853            while let Some(selection) = selections_iter.next() {
13854                if selection.start != selection.end {
13855                    only_carets = false;
13856                }
13857
13858                if same_text_selected {
13859                    if selected_text.is_none() {
13860                        selected_text =
13861                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13862                    }
13863
13864                    if let Some(next_selection) = selections_iter.peek() {
13865                        if next_selection.range().len() == selection.range().len() {
13866                            let next_selected_text = buffer
13867                                .text_for_range(next_selection.range())
13868                                .collect::<String>();
13869                            if Some(next_selected_text) != selected_text {
13870                                same_text_selected = false;
13871                                selected_text = None;
13872                            }
13873                        } else {
13874                            same_text_selected = false;
13875                            selected_text = None;
13876                        }
13877                    }
13878                }
13879            }
13880
13881            if only_carets {
13882                for selection in &mut selections {
13883                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13884                    selection.start = word_range.start;
13885                    selection.end = word_range.end;
13886                    selection.goal = SelectionGoal::None;
13887                    selection.reversed = false;
13888                    self.select_match_ranges(
13889                        selection.start..selection.end,
13890                        selection.reversed,
13891                        replace_newest,
13892                        autoscroll,
13893                        window,
13894                        cx,
13895                    );
13896                }
13897
13898                if selections.len() == 1 {
13899                    let selection = selections
13900                        .last()
13901                        .expect("ensured that there's only one selection");
13902                    let query = buffer
13903                        .text_for_range(selection.start..selection.end)
13904                        .collect::<String>();
13905                    let is_empty = query.is_empty();
13906                    let select_state = SelectNextState {
13907                        query: AhoCorasick::new(&[query])?,
13908                        wordwise: true,
13909                        done: is_empty,
13910                    };
13911                    self.select_next_state = Some(select_state);
13912                } else {
13913                    self.select_next_state = None;
13914                }
13915            } else if let Some(selected_text) = selected_text {
13916                self.select_next_state = Some(SelectNextState {
13917                    query: AhoCorasick::new(&[selected_text])?,
13918                    wordwise: false,
13919                    done: false,
13920                });
13921                self.select_next_match_internal(
13922                    display_map,
13923                    replace_newest,
13924                    autoscroll,
13925                    window,
13926                    cx,
13927                )?;
13928            }
13929        }
13930        Ok(())
13931    }
13932
13933    pub fn select_all_matches(
13934        &mut self,
13935        _action: &SelectAllMatches,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) -> Result<()> {
13939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13940
13941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13942
13943        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13944        let Some(select_next_state) = self.select_next_state.as_mut() else {
13945            return Ok(());
13946        };
13947        if select_next_state.done {
13948            return Ok(());
13949        }
13950
13951        let mut new_selections = Vec::new();
13952
13953        let reversed = self.selections.oldest::<usize>(cx).reversed;
13954        let buffer = &display_map.buffer_snapshot;
13955        let query_matches = select_next_state
13956            .query
13957            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13958
13959        for query_match in query_matches.into_iter() {
13960            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13961            let offset_range = if reversed {
13962                query_match.end()..query_match.start()
13963            } else {
13964                query_match.start()..query_match.end()
13965            };
13966
13967            if !select_next_state.wordwise
13968                || (!buffer.is_inside_word(offset_range.start, false)
13969                    && !buffer.is_inside_word(offset_range.end, false))
13970            {
13971                new_selections.push(offset_range.start..offset_range.end);
13972            }
13973        }
13974
13975        select_next_state.done = true;
13976
13977        if new_selections.is_empty() {
13978            log::error!("bug: new_selections is empty in select_all_matches");
13979            return Ok(());
13980        }
13981
13982        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13983        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13984            selections.select_ranges(new_selections)
13985        });
13986
13987        Ok(())
13988    }
13989
13990    pub fn select_next(
13991        &mut self,
13992        action: &SelectNext,
13993        window: &mut Window,
13994        cx: &mut Context<Self>,
13995    ) -> Result<()> {
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13998        self.select_next_match_internal(
13999            &display_map,
14000            action.replace_newest,
14001            Some(Autoscroll::newest()),
14002            window,
14003            cx,
14004        )?;
14005        Ok(())
14006    }
14007
14008    pub fn select_previous(
14009        &mut self,
14010        action: &SelectPrevious,
14011        window: &mut Window,
14012        cx: &mut Context<Self>,
14013    ) -> Result<()> {
14014        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14016        let buffer = &display_map.buffer_snapshot;
14017        let mut selections = self.selections.all::<usize>(cx);
14018        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14019            let query = &select_prev_state.query;
14020            if !select_prev_state.done {
14021                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14022                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14023                let mut next_selected_range = None;
14024                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14025                let bytes_before_last_selection =
14026                    buffer.reversed_bytes_in_range(0..last_selection.start);
14027                let bytes_after_first_selection =
14028                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14029                let query_matches = query
14030                    .stream_find_iter(bytes_before_last_selection)
14031                    .map(|result| (last_selection.start, result))
14032                    .chain(
14033                        query
14034                            .stream_find_iter(bytes_after_first_selection)
14035                            .map(|result| (buffer.len(), result)),
14036                    );
14037                for (end_offset, query_match) in query_matches {
14038                    let query_match = query_match.unwrap(); // can only fail due to I/O
14039                    let offset_range =
14040                        end_offset - query_match.end()..end_offset - query_match.start();
14041
14042                    if !select_prev_state.wordwise
14043                        || (!buffer.is_inside_word(offset_range.start, false)
14044                            && !buffer.is_inside_word(offset_range.end, false))
14045                    {
14046                        next_selected_range = Some(offset_range);
14047                        break;
14048                    }
14049                }
14050
14051                if let Some(next_selected_range) = next_selected_range {
14052                    self.select_match_ranges(
14053                        next_selected_range,
14054                        last_selection.reversed,
14055                        action.replace_newest,
14056                        Some(Autoscroll::newest()),
14057                        window,
14058                        cx,
14059                    );
14060                } else {
14061                    select_prev_state.done = true;
14062                }
14063            }
14064
14065            self.select_prev_state = Some(select_prev_state);
14066        } else {
14067            let mut only_carets = true;
14068            let mut same_text_selected = true;
14069            let mut selected_text = None;
14070
14071            let mut selections_iter = selections.iter().peekable();
14072            while let Some(selection) = selections_iter.next() {
14073                if selection.start != selection.end {
14074                    only_carets = false;
14075                }
14076
14077                if same_text_selected {
14078                    if selected_text.is_none() {
14079                        selected_text =
14080                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14081                    }
14082
14083                    if let Some(next_selection) = selections_iter.peek() {
14084                        if next_selection.range().len() == selection.range().len() {
14085                            let next_selected_text = buffer
14086                                .text_for_range(next_selection.range())
14087                                .collect::<String>();
14088                            if Some(next_selected_text) != selected_text {
14089                                same_text_selected = false;
14090                                selected_text = None;
14091                            }
14092                        } else {
14093                            same_text_selected = false;
14094                            selected_text = None;
14095                        }
14096                    }
14097                }
14098            }
14099
14100            if only_carets {
14101                for selection in &mut selections {
14102                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14103                    selection.start = word_range.start;
14104                    selection.end = word_range.end;
14105                    selection.goal = SelectionGoal::None;
14106                    selection.reversed = false;
14107                    self.select_match_ranges(
14108                        selection.start..selection.end,
14109                        selection.reversed,
14110                        action.replace_newest,
14111                        Some(Autoscroll::newest()),
14112                        window,
14113                        cx,
14114                    );
14115                }
14116                if selections.len() == 1 {
14117                    let selection = selections
14118                        .last()
14119                        .expect("ensured that there's only one selection");
14120                    let query = buffer
14121                        .text_for_range(selection.start..selection.end)
14122                        .collect::<String>();
14123                    let is_empty = query.is_empty();
14124                    let select_state = SelectNextState {
14125                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14126                        wordwise: true,
14127                        done: is_empty,
14128                    };
14129                    self.select_prev_state = Some(select_state);
14130                } else {
14131                    self.select_prev_state = None;
14132                }
14133            } else if let Some(selected_text) = selected_text {
14134                self.select_prev_state = Some(SelectNextState {
14135                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14136                    wordwise: false,
14137                    done: false,
14138                });
14139                self.select_previous(action, window, cx)?;
14140            }
14141        }
14142        Ok(())
14143    }
14144
14145    pub fn find_next_match(
14146        &mut self,
14147        _: &FindNextMatch,
14148        window: &mut Window,
14149        cx: &mut Context<Self>,
14150    ) -> Result<()> {
14151        let selections = self.selections.disjoint_anchors();
14152        match selections.first() {
14153            Some(first) if selections.len() >= 2 => {
14154                self.change_selections(Default::default(), window, cx, |s| {
14155                    s.select_ranges([first.range()]);
14156                });
14157            }
14158            _ => self.select_next(
14159                &SelectNext {
14160                    replace_newest: true,
14161                },
14162                window,
14163                cx,
14164            )?,
14165        }
14166        Ok(())
14167    }
14168
14169    pub fn find_previous_match(
14170        &mut self,
14171        _: &FindPreviousMatch,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) -> Result<()> {
14175        let selections = self.selections.disjoint_anchors();
14176        match selections.last() {
14177            Some(last) if selections.len() >= 2 => {
14178                self.change_selections(Default::default(), window, cx, |s| {
14179                    s.select_ranges([last.range()]);
14180                });
14181            }
14182            _ => self.select_previous(
14183                &SelectPrevious {
14184                    replace_newest: true,
14185                },
14186                window,
14187                cx,
14188            )?,
14189        }
14190        Ok(())
14191    }
14192
14193    pub fn toggle_comments(
14194        &mut self,
14195        action: &ToggleComments,
14196        window: &mut Window,
14197        cx: &mut Context<Self>,
14198    ) {
14199        if self.read_only(cx) {
14200            return;
14201        }
14202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14203        let text_layout_details = &self.text_layout_details(window);
14204        self.transact(window, cx, |this, window, cx| {
14205            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14206            let mut edits = Vec::new();
14207            let mut selection_edit_ranges = Vec::new();
14208            let mut last_toggled_row = None;
14209            let snapshot = this.buffer.read(cx).read(cx);
14210            let empty_str: Arc<str> = Arc::default();
14211            let mut suffixes_inserted = Vec::new();
14212            let ignore_indent = action.ignore_indent;
14213
14214            fn comment_prefix_range(
14215                snapshot: &MultiBufferSnapshot,
14216                row: MultiBufferRow,
14217                comment_prefix: &str,
14218                comment_prefix_whitespace: &str,
14219                ignore_indent: bool,
14220            ) -> Range<Point> {
14221                let indent_size = if ignore_indent {
14222                    0
14223                } else {
14224                    snapshot.indent_size_for_line(row).len
14225                };
14226
14227                let start = Point::new(row.0, indent_size);
14228
14229                let mut line_bytes = snapshot
14230                    .bytes_in_range(start..snapshot.max_point())
14231                    .flatten()
14232                    .copied();
14233
14234                // If this line currently begins with the line comment prefix, then record
14235                // the range containing the prefix.
14236                if line_bytes
14237                    .by_ref()
14238                    .take(comment_prefix.len())
14239                    .eq(comment_prefix.bytes())
14240                {
14241                    // Include any whitespace that matches the comment prefix.
14242                    let matching_whitespace_len = line_bytes
14243                        .zip(comment_prefix_whitespace.bytes())
14244                        .take_while(|(a, b)| a == b)
14245                        .count() as u32;
14246                    let end = Point::new(
14247                        start.row,
14248                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14249                    );
14250                    start..end
14251                } else {
14252                    start..start
14253                }
14254            }
14255
14256            fn comment_suffix_range(
14257                snapshot: &MultiBufferSnapshot,
14258                row: MultiBufferRow,
14259                comment_suffix: &str,
14260                comment_suffix_has_leading_space: bool,
14261            ) -> Range<Point> {
14262                let end = Point::new(row.0, snapshot.line_len(row));
14263                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14264
14265                let mut line_end_bytes = snapshot
14266                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14267                    .flatten()
14268                    .copied();
14269
14270                let leading_space_len = if suffix_start_column > 0
14271                    && line_end_bytes.next() == Some(b' ')
14272                    && comment_suffix_has_leading_space
14273                {
14274                    1
14275                } else {
14276                    0
14277                };
14278
14279                // If this line currently begins with the line comment prefix, then record
14280                // the range containing the prefix.
14281                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14282                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14283                    start..end
14284                } else {
14285                    end..end
14286                }
14287            }
14288
14289            // TODO: Handle selections that cross excerpts
14290            for selection in &mut selections {
14291                let start_column = snapshot
14292                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14293                    .len;
14294                let language = if let Some(language) =
14295                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14296                {
14297                    language
14298                } else {
14299                    continue;
14300                };
14301
14302                selection_edit_ranges.clear();
14303
14304                // If multiple selections contain a given row, avoid processing that
14305                // row more than once.
14306                let mut start_row = MultiBufferRow(selection.start.row);
14307                if last_toggled_row == Some(start_row) {
14308                    start_row = start_row.next_row();
14309                }
14310                let end_row =
14311                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14312                        MultiBufferRow(selection.end.row - 1)
14313                    } else {
14314                        MultiBufferRow(selection.end.row)
14315                    };
14316                last_toggled_row = Some(end_row);
14317
14318                if start_row > end_row {
14319                    continue;
14320                }
14321
14322                // If the language has line comments, toggle those.
14323                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14324
14325                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14326                if ignore_indent {
14327                    full_comment_prefixes = full_comment_prefixes
14328                        .into_iter()
14329                        .map(|s| Arc::from(s.trim_end()))
14330                        .collect();
14331                }
14332
14333                if !full_comment_prefixes.is_empty() {
14334                    let first_prefix = full_comment_prefixes
14335                        .first()
14336                        .expect("prefixes is non-empty");
14337                    let prefix_trimmed_lengths = full_comment_prefixes
14338                        .iter()
14339                        .map(|p| p.trim_end_matches(' ').len())
14340                        .collect::<SmallVec<[usize; 4]>>();
14341
14342                    let mut all_selection_lines_are_comments = true;
14343
14344                    for row in start_row.0..=end_row.0 {
14345                        let row = MultiBufferRow(row);
14346                        if start_row < end_row && snapshot.is_line_blank(row) {
14347                            continue;
14348                        }
14349
14350                        let prefix_range = full_comment_prefixes
14351                            .iter()
14352                            .zip(prefix_trimmed_lengths.iter().copied())
14353                            .map(|(prefix, trimmed_prefix_len)| {
14354                                comment_prefix_range(
14355                                    snapshot.deref(),
14356                                    row,
14357                                    &prefix[..trimmed_prefix_len],
14358                                    &prefix[trimmed_prefix_len..],
14359                                    ignore_indent,
14360                                )
14361                            })
14362                            .max_by_key(|range| range.end.column - range.start.column)
14363                            .expect("prefixes is non-empty");
14364
14365                        if prefix_range.is_empty() {
14366                            all_selection_lines_are_comments = false;
14367                        }
14368
14369                        selection_edit_ranges.push(prefix_range);
14370                    }
14371
14372                    if all_selection_lines_are_comments {
14373                        edits.extend(
14374                            selection_edit_ranges
14375                                .iter()
14376                                .cloned()
14377                                .map(|range| (range, empty_str.clone())),
14378                        );
14379                    } else {
14380                        let min_column = selection_edit_ranges
14381                            .iter()
14382                            .map(|range| range.start.column)
14383                            .min()
14384                            .unwrap_or(0);
14385                        edits.extend(selection_edit_ranges.iter().map(|range| {
14386                            let position = Point::new(range.start.row, min_column);
14387                            (position..position, first_prefix.clone())
14388                        }));
14389                    }
14390                } else if let Some(BlockCommentConfig {
14391                    start: full_comment_prefix,
14392                    end: comment_suffix,
14393                    ..
14394                }) = language.block_comment()
14395                {
14396                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14397                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14398                    let prefix_range = comment_prefix_range(
14399                        snapshot.deref(),
14400                        start_row,
14401                        comment_prefix,
14402                        comment_prefix_whitespace,
14403                        ignore_indent,
14404                    );
14405                    let suffix_range = comment_suffix_range(
14406                        snapshot.deref(),
14407                        end_row,
14408                        comment_suffix.trim_start_matches(' '),
14409                        comment_suffix.starts_with(' '),
14410                    );
14411
14412                    if prefix_range.is_empty() || suffix_range.is_empty() {
14413                        edits.push((
14414                            prefix_range.start..prefix_range.start,
14415                            full_comment_prefix.clone(),
14416                        ));
14417                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14418                        suffixes_inserted.push((end_row, comment_suffix.len()));
14419                    } else {
14420                        edits.push((prefix_range, empty_str.clone()));
14421                        edits.push((suffix_range, empty_str.clone()));
14422                    }
14423                } else {
14424                    continue;
14425                }
14426            }
14427
14428            drop(snapshot);
14429            this.buffer.update(cx, |buffer, cx| {
14430                buffer.edit(edits, None, cx);
14431            });
14432
14433            // Adjust selections so that they end before any comment suffixes that
14434            // were inserted.
14435            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14436            let mut selections = this.selections.all::<Point>(cx);
14437            let snapshot = this.buffer.read(cx).read(cx);
14438            for selection in &mut selections {
14439                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14440                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14441                        Ordering::Less => {
14442                            suffixes_inserted.next();
14443                            continue;
14444                        }
14445                        Ordering::Greater => break,
14446                        Ordering::Equal => {
14447                            if selection.end.column == snapshot.line_len(row) {
14448                                if selection.is_empty() {
14449                                    selection.start.column -= suffix_len as u32;
14450                                }
14451                                selection.end.column -= suffix_len as u32;
14452                            }
14453                            break;
14454                        }
14455                    }
14456                }
14457            }
14458
14459            drop(snapshot);
14460            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14461
14462            let selections = this.selections.all::<Point>(cx);
14463            let selections_on_single_row = selections.windows(2).all(|selections| {
14464                selections[0].start.row == selections[1].start.row
14465                    && selections[0].end.row == selections[1].end.row
14466                    && selections[0].start.row == selections[0].end.row
14467            });
14468            let selections_selecting = selections
14469                .iter()
14470                .any(|selection| selection.start != selection.end);
14471            let advance_downwards = action.advance_downwards
14472                && selections_on_single_row
14473                && !selections_selecting
14474                && !matches!(this.mode, EditorMode::SingleLine { .. });
14475
14476            if advance_downwards {
14477                let snapshot = this.buffer.read(cx).snapshot(cx);
14478
14479                this.change_selections(Default::default(), window, cx, |s| {
14480                    s.move_cursors_with(|display_snapshot, display_point, _| {
14481                        let mut point = display_point.to_point(display_snapshot);
14482                        point.row += 1;
14483                        point = snapshot.clip_point(point, Bias::Left);
14484                        let display_point = point.to_display_point(display_snapshot);
14485                        let goal = SelectionGoal::HorizontalPosition(
14486                            display_snapshot
14487                                .x_for_display_point(display_point, text_layout_details)
14488                                .into(),
14489                        );
14490                        (display_point, goal)
14491                    })
14492                });
14493            }
14494        });
14495    }
14496
14497    pub fn select_enclosing_symbol(
14498        &mut self,
14499        _: &SelectEnclosingSymbol,
14500        window: &mut Window,
14501        cx: &mut Context<Self>,
14502    ) {
14503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14504
14505        let buffer = self.buffer.read(cx).snapshot(cx);
14506        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14507
14508        fn update_selection(
14509            selection: &Selection<usize>,
14510            buffer_snap: &MultiBufferSnapshot,
14511        ) -> Option<Selection<usize>> {
14512            let cursor = selection.head();
14513            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14514            for symbol in symbols.iter().rev() {
14515                let start = symbol.range.start.to_offset(buffer_snap);
14516                let end = symbol.range.end.to_offset(buffer_snap);
14517                let new_range = start..end;
14518                if start < selection.start || end > selection.end {
14519                    return Some(Selection {
14520                        id: selection.id,
14521                        start: new_range.start,
14522                        end: new_range.end,
14523                        goal: SelectionGoal::None,
14524                        reversed: selection.reversed,
14525                    });
14526                }
14527            }
14528            None
14529        }
14530
14531        let mut selected_larger_symbol = false;
14532        let new_selections = old_selections
14533            .iter()
14534            .map(|selection| match update_selection(selection, &buffer) {
14535                Some(new_selection) => {
14536                    if new_selection.range() != selection.range() {
14537                        selected_larger_symbol = true;
14538                    }
14539                    new_selection
14540                }
14541                None => selection.clone(),
14542            })
14543            .collect::<Vec<_>>();
14544
14545        if selected_larger_symbol {
14546            self.change_selections(Default::default(), window, cx, |s| {
14547                s.select(new_selections);
14548            });
14549        }
14550    }
14551
14552    pub fn select_larger_syntax_node(
14553        &mut self,
14554        _: &SelectLargerSyntaxNode,
14555        window: &mut Window,
14556        cx: &mut Context<Self>,
14557    ) {
14558        let Some(visible_row_count) = self.visible_row_count() else {
14559            return;
14560        };
14561        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14562        if old_selections.is_empty() {
14563            return;
14564        }
14565
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14567
14568        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14569        let buffer = self.buffer.read(cx).snapshot(cx);
14570
14571        let mut selected_larger_node = false;
14572        let mut new_selections = old_selections
14573            .iter()
14574            .map(|selection| {
14575                let old_range = selection.start..selection.end;
14576
14577                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14578                    // manually select word at selection
14579                    if ["string_content", "inline"].contains(&node.kind()) {
14580                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14581                        // ignore if word is already selected
14582                        if !word_range.is_empty() && old_range != word_range {
14583                            let (last_word_range, _) =
14584                                buffer.surrounding_word(old_range.end, false);
14585                            // only select word if start and end point belongs to same word
14586                            if word_range == last_word_range {
14587                                selected_larger_node = true;
14588                                return Selection {
14589                                    id: selection.id,
14590                                    start: word_range.start,
14591                                    end: word_range.end,
14592                                    goal: SelectionGoal::None,
14593                                    reversed: selection.reversed,
14594                                };
14595                            }
14596                        }
14597                    }
14598                }
14599
14600                let mut new_range = old_range.clone();
14601                while let Some((_node, containing_range)) =
14602                    buffer.syntax_ancestor(new_range.clone())
14603                {
14604                    new_range = match containing_range {
14605                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14606                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14607                    };
14608                    if !display_map.intersects_fold(new_range.start)
14609                        && !display_map.intersects_fold(new_range.end)
14610                    {
14611                        break;
14612                    }
14613                }
14614
14615                selected_larger_node |= new_range != old_range;
14616                Selection {
14617                    id: selection.id,
14618                    start: new_range.start,
14619                    end: new_range.end,
14620                    goal: SelectionGoal::None,
14621                    reversed: selection.reversed,
14622                }
14623            })
14624            .collect::<Vec<_>>();
14625
14626        if !selected_larger_node {
14627            return; // don't put this call in the history
14628        }
14629
14630        // scroll based on transformation done to the last selection created by the user
14631        let (last_old, last_new) = old_selections
14632            .last()
14633            .zip(new_selections.last().cloned())
14634            .expect("old_selections isn't empty");
14635
14636        // revert selection
14637        let is_selection_reversed = {
14638            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14639            new_selections.last_mut().expect("checked above").reversed =
14640                should_newest_selection_be_reversed;
14641            should_newest_selection_be_reversed
14642        };
14643
14644        if selected_larger_node {
14645            self.select_syntax_node_history.disable_clearing = true;
14646            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14647                s.select(new_selections.clone());
14648            });
14649            self.select_syntax_node_history.disable_clearing = false;
14650        }
14651
14652        let start_row = last_new.start.to_display_point(&display_map).row().0;
14653        let end_row = last_new.end.to_display_point(&display_map).row().0;
14654        let selection_height = end_row - start_row + 1;
14655        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14656
14657        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14658        let scroll_behavior = if fits_on_the_screen {
14659            self.request_autoscroll(Autoscroll::fit(), cx);
14660            SelectSyntaxNodeScrollBehavior::FitSelection
14661        } else if is_selection_reversed {
14662            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14663            SelectSyntaxNodeScrollBehavior::CursorTop
14664        } else {
14665            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14666            SelectSyntaxNodeScrollBehavior::CursorBottom
14667        };
14668
14669        self.select_syntax_node_history.push((
14670            old_selections,
14671            scroll_behavior,
14672            is_selection_reversed,
14673        ));
14674    }
14675
14676    pub fn select_smaller_syntax_node(
14677        &mut self,
14678        _: &SelectSmallerSyntaxNode,
14679        window: &mut Window,
14680        cx: &mut Context<Self>,
14681    ) {
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683
14684        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14685            self.select_syntax_node_history.pop()
14686        {
14687            if let Some(selection) = selections.last_mut() {
14688                selection.reversed = is_selection_reversed;
14689            }
14690
14691            self.select_syntax_node_history.disable_clearing = true;
14692            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14693                s.select(selections.to_vec());
14694            });
14695            self.select_syntax_node_history.disable_clearing = false;
14696
14697            match scroll_behavior {
14698                SelectSyntaxNodeScrollBehavior::CursorTop => {
14699                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14700                }
14701                SelectSyntaxNodeScrollBehavior::FitSelection => {
14702                    self.request_autoscroll(Autoscroll::fit(), cx);
14703                }
14704                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14705                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14706                }
14707            }
14708        }
14709    }
14710
14711    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14712        if !EditorSettings::get_global(cx).gutter.runnables {
14713            self.clear_tasks();
14714            return Task::ready(());
14715        }
14716        let project = self.project.as_ref().map(Entity::downgrade);
14717        let task_sources = self.lsp_task_sources(cx);
14718        let multi_buffer = self.buffer.downgrade();
14719        cx.spawn_in(window, async move |editor, cx| {
14720            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14721            let Some(project) = project.and_then(|p| p.upgrade()) else {
14722                return;
14723            };
14724            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14725                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14726            }) else {
14727                return;
14728            };
14729
14730            let hide_runnables = project
14731                .update(cx, |project, cx| {
14732                    // Do not display any test indicators in non-dev server remote projects.
14733                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14734                })
14735                .unwrap_or(true);
14736            if hide_runnables {
14737                return;
14738            }
14739            let new_rows =
14740                cx.background_spawn({
14741                    let snapshot = display_snapshot.clone();
14742                    async move {
14743                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14744                    }
14745                })
14746                    .await;
14747            let Ok(lsp_tasks) =
14748                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14749            else {
14750                return;
14751            };
14752            let lsp_tasks = lsp_tasks.await;
14753
14754            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14755                lsp_tasks
14756                    .into_iter()
14757                    .flat_map(|(kind, tasks)| {
14758                        tasks.into_iter().filter_map(move |(location, task)| {
14759                            Some((kind.clone(), location?, task))
14760                        })
14761                    })
14762                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14763                        let buffer = location.target.buffer;
14764                        let buffer_snapshot = buffer.read(cx).snapshot();
14765                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14766                            |(excerpt_id, snapshot, _)| {
14767                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14768                                    display_snapshot
14769                                        .buffer_snapshot
14770                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14771                                } else {
14772                                    None
14773                                }
14774                            },
14775                        );
14776                        if let Some(offset) = offset {
14777                            let task_buffer_range =
14778                                location.target.range.to_point(&buffer_snapshot);
14779                            let context_buffer_range =
14780                                task_buffer_range.to_offset(&buffer_snapshot);
14781                            let context_range = BufferOffset(context_buffer_range.start)
14782                                ..BufferOffset(context_buffer_range.end);
14783
14784                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14785                                .or_insert_with(|| RunnableTasks {
14786                                    templates: Vec::new(),
14787                                    offset,
14788                                    column: task_buffer_range.start.column,
14789                                    extra_variables: HashMap::default(),
14790                                    context_range,
14791                                })
14792                                .templates
14793                                .push((kind, task.original_task().clone()));
14794                        }
14795
14796                        acc
14797                    })
14798            }) else {
14799                return;
14800            };
14801
14802            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14803                buffer.language_settings(cx).tasks.prefer_lsp
14804            }) else {
14805                return;
14806            };
14807
14808            let rows = Self::runnable_rows(
14809                project,
14810                display_snapshot,
14811                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14812                new_rows,
14813                cx.clone(),
14814            )
14815            .await;
14816            editor
14817                .update(cx, |editor, _| {
14818                    editor.clear_tasks();
14819                    for (key, mut value) in rows {
14820                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14821                            value.templates.extend(lsp_tasks.templates);
14822                        }
14823
14824                        editor.insert_tasks(key, value);
14825                    }
14826                    for (key, value) in lsp_tasks_by_rows {
14827                        editor.insert_tasks(key, value);
14828                    }
14829                })
14830                .ok();
14831        })
14832    }
14833    fn fetch_runnable_ranges(
14834        snapshot: &DisplaySnapshot,
14835        range: Range<Anchor>,
14836    ) -> Vec<language::RunnableRange> {
14837        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14838    }
14839
14840    fn runnable_rows(
14841        project: Entity<Project>,
14842        snapshot: DisplaySnapshot,
14843        prefer_lsp: bool,
14844        runnable_ranges: Vec<RunnableRange>,
14845        cx: AsyncWindowContext,
14846    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14847        cx.spawn(async move |cx| {
14848            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14849            for mut runnable in runnable_ranges {
14850                let Some(tasks) = cx
14851                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14852                    .ok()
14853                else {
14854                    continue;
14855                };
14856                let mut tasks = tasks.await;
14857
14858                if prefer_lsp {
14859                    tasks.retain(|(task_kind, _)| {
14860                        !matches!(task_kind, TaskSourceKind::Language { .. })
14861                    });
14862                }
14863                if tasks.is_empty() {
14864                    continue;
14865                }
14866
14867                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14868                let Some(row) = snapshot
14869                    .buffer_snapshot
14870                    .buffer_line_for_row(MultiBufferRow(point.row))
14871                    .map(|(_, range)| range.start.row)
14872                else {
14873                    continue;
14874                };
14875
14876                let context_range =
14877                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14878                runnable_rows.push((
14879                    (runnable.buffer_id, row),
14880                    RunnableTasks {
14881                        templates: tasks,
14882                        offset: snapshot
14883                            .buffer_snapshot
14884                            .anchor_before(runnable.run_range.start),
14885                        context_range,
14886                        column: point.column,
14887                        extra_variables: runnable.extra_captures,
14888                    },
14889                ));
14890            }
14891            runnable_rows
14892        })
14893    }
14894
14895    fn templates_with_tags(
14896        project: &Entity<Project>,
14897        runnable: &mut Runnable,
14898        cx: &mut App,
14899    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14900        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14901            let (worktree_id, file) = project
14902                .buffer_for_id(runnable.buffer, cx)
14903                .and_then(|buffer| buffer.read(cx).file())
14904                .map(|file| (file.worktree_id(cx), file.clone()))
14905                .unzip();
14906
14907            (
14908                project.task_store().read(cx).task_inventory().cloned(),
14909                worktree_id,
14910                file,
14911            )
14912        });
14913
14914        let tags = mem::take(&mut runnable.tags);
14915        let language = runnable.language.clone();
14916        cx.spawn(async move |cx| {
14917            let mut templates_with_tags = Vec::new();
14918            if let Some(inventory) = inventory {
14919                for RunnableTag(tag) in tags {
14920                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14921                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14922                    }) else {
14923                        return templates_with_tags;
14924                    };
14925                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14926                        move |(_, template)| {
14927                            template.tags.iter().any(|source_tag| source_tag == &tag)
14928                        },
14929                    ));
14930                }
14931            }
14932            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14933
14934            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14935                // Strongest source wins; if we have worktree tag binding, prefer that to
14936                // global and language bindings;
14937                // if we have a global binding, prefer that to language binding.
14938                let first_mismatch = templates_with_tags
14939                    .iter()
14940                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14941                if let Some(index) = first_mismatch {
14942                    templates_with_tags.truncate(index);
14943                }
14944            }
14945
14946            templates_with_tags
14947        })
14948    }
14949
14950    pub fn move_to_enclosing_bracket(
14951        &mut self,
14952        _: &MoveToEnclosingBracket,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957        self.change_selections(Default::default(), window, cx, |s| {
14958            s.move_offsets_with(|snapshot, selection| {
14959                let Some(enclosing_bracket_ranges) =
14960                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14961                else {
14962                    return;
14963                };
14964
14965                let mut best_length = usize::MAX;
14966                let mut best_inside = false;
14967                let mut best_in_bracket_range = false;
14968                let mut best_destination = None;
14969                for (open, close) in enclosing_bracket_ranges {
14970                    let close = close.to_inclusive();
14971                    let length = close.end() - open.start;
14972                    let inside = selection.start >= open.end && selection.end <= *close.start();
14973                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14974                        || close.contains(&selection.head());
14975
14976                    // If best is next to a bracket and current isn't, skip
14977                    if !in_bracket_range && best_in_bracket_range {
14978                        continue;
14979                    }
14980
14981                    // Prefer smaller lengths unless best is inside and current isn't
14982                    if length > best_length && (best_inside || !inside) {
14983                        continue;
14984                    }
14985
14986                    best_length = length;
14987                    best_inside = inside;
14988                    best_in_bracket_range = in_bracket_range;
14989                    best_destination = Some(
14990                        if close.contains(&selection.start) && close.contains(&selection.end) {
14991                            if inside { open.end } else { open.start }
14992                        } else if inside {
14993                            *close.start()
14994                        } else {
14995                            *close.end()
14996                        },
14997                    );
14998                }
14999
15000                if let Some(destination) = best_destination {
15001                    selection.collapse_to(destination, SelectionGoal::None);
15002                }
15003            })
15004        });
15005    }
15006
15007    pub fn undo_selection(
15008        &mut self,
15009        _: &UndoSelection,
15010        window: &mut Window,
15011        cx: &mut Context<Self>,
15012    ) {
15013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15014        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15015            self.selection_history.mode = SelectionHistoryMode::Undoing;
15016            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15017                this.end_selection(window, cx);
15018                this.change_selections(
15019                    SelectionEffects::scroll(Autoscroll::newest()),
15020                    window,
15021                    cx,
15022                    |s| s.select_anchors(entry.selections.to_vec()),
15023                );
15024            });
15025            self.selection_history.mode = SelectionHistoryMode::Normal;
15026
15027            self.select_next_state = entry.select_next_state;
15028            self.select_prev_state = entry.select_prev_state;
15029            self.add_selections_state = entry.add_selections_state;
15030        }
15031    }
15032
15033    pub fn redo_selection(
15034        &mut self,
15035        _: &RedoSelection,
15036        window: &mut Window,
15037        cx: &mut Context<Self>,
15038    ) {
15039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15040        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15041            self.selection_history.mode = SelectionHistoryMode::Redoing;
15042            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15043                this.end_selection(window, cx);
15044                this.change_selections(
15045                    SelectionEffects::scroll(Autoscroll::newest()),
15046                    window,
15047                    cx,
15048                    |s| s.select_anchors(entry.selections.to_vec()),
15049                );
15050            });
15051            self.selection_history.mode = SelectionHistoryMode::Normal;
15052
15053            self.select_next_state = entry.select_next_state;
15054            self.select_prev_state = entry.select_prev_state;
15055            self.add_selections_state = entry.add_selections_state;
15056        }
15057    }
15058
15059    pub fn expand_excerpts(
15060        &mut self,
15061        action: &ExpandExcerpts,
15062        _: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) {
15065        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15066    }
15067
15068    pub fn expand_excerpts_down(
15069        &mut self,
15070        action: &ExpandExcerptsDown,
15071        _: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15075    }
15076
15077    pub fn expand_excerpts_up(
15078        &mut self,
15079        action: &ExpandExcerptsUp,
15080        _: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15084    }
15085
15086    pub fn expand_excerpts_for_direction(
15087        &mut self,
15088        lines: u32,
15089        direction: ExpandExcerptDirection,
15090
15091        cx: &mut Context<Self>,
15092    ) {
15093        let selections = self.selections.disjoint_anchors();
15094
15095        let lines = if lines == 0 {
15096            EditorSettings::get_global(cx).expand_excerpt_lines
15097        } else {
15098            lines
15099        };
15100
15101        self.buffer.update(cx, |buffer, cx| {
15102            let snapshot = buffer.snapshot(cx);
15103            let mut excerpt_ids = selections
15104                .iter()
15105                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15106                .collect::<Vec<_>>();
15107            excerpt_ids.sort();
15108            excerpt_ids.dedup();
15109            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15110        })
15111    }
15112
15113    pub fn expand_excerpt(
15114        &mut self,
15115        excerpt: ExcerptId,
15116        direction: ExpandExcerptDirection,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) {
15120        let current_scroll_position = self.scroll_position(cx);
15121        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15122        let mut should_scroll_up = false;
15123
15124        if direction == ExpandExcerptDirection::Down {
15125            let multi_buffer = self.buffer.read(cx);
15126            let snapshot = multi_buffer.snapshot(cx);
15127            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15128                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15129                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15130                        let buffer_snapshot = buffer.read(cx).snapshot();
15131                        let excerpt_end_row =
15132                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15133                        let last_row = buffer_snapshot.max_point().row;
15134                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15135                        should_scroll_up = lines_below >= lines_to_expand;
15136                    }
15137                }
15138            }
15139        }
15140
15141        self.buffer.update(cx, |buffer, cx| {
15142            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15143        });
15144
15145        if should_scroll_up {
15146            let new_scroll_position =
15147                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15148            self.set_scroll_position(new_scroll_position, window, cx);
15149        }
15150    }
15151
15152    pub fn go_to_singleton_buffer_point(
15153        &mut self,
15154        point: Point,
15155        window: &mut Window,
15156        cx: &mut Context<Self>,
15157    ) {
15158        self.go_to_singleton_buffer_range(point..point, window, cx);
15159    }
15160
15161    pub fn go_to_singleton_buffer_range(
15162        &mut self,
15163        range: Range<Point>,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) {
15167        let multibuffer = self.buffer().read(cx);
15168        let Some(buffer) = multibuffer.as_singleton() else {
15169            return;
15170        };
15171        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15172            return;
15173        };
15174        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15175            return;
15176        };
15177        self.change_selections(
15178            SelectionEffects::default().nav_history(true),
15179            window,
15180            cx,
15181            |s| s.select_anchor_ranges([start..end]),
15182        );
15183    }
15184
15185    pub fn go_to_diagnostic(
15186        &mut self,
15187        action: &GoToDiagnostic,
15188        window: &mut Window,
15189        cx: &mut Context<Self>,
15190    ) {
15191        if !self.diagnostics_enabled() {
15192            return;
15193        }
15194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15195        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15196    }
15197
15198    pub fn go_to_prev_diagnostic(
15199        &mut self,
15200        action: &GoToPreviousDiagnostic,
15201        window: &mut Window,
15202        cx: &mut Context<Self>,
15203    ) {
15204        if !self.diagnostics_enabled() {
15205            return;
15206        }
15207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15208        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15209    }
15210
15211    pub fn go_to_diagnostic_impl(
15212        &mut self,
15213        direction: Direction,
15214        severity: GoToDiagnosticSeverityFilter,
15215        window: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) {
15218        let buffer = self.buffer.read(cx).snapshot(cx);
15219        let selection = self.selections.newest::<usize>(cx);
15220
15221        let mut active_group_id = None;
15222        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15223            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15224                active_group_id = Some(active_group.group_id);
15225            }
15226        }
15227
15228        fn filtered(
15229            snapshot: EditorSnapshot,
15230            severity: GoToDiagnosticSeverityFilter,
15231            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15232        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15233            diagnostics
15234                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15235                .filter(|entry| entry.range.start != entry.range.end)
15236                .filter(|entry| !entry.diagnostic.is_unnecessary)
15237                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15238        }
15239
15240        let snapshot = self.snapshot(window, cx);
15241        let before = filtered(
15242            snapshot.clone(),
15243            severity,
15244            buffer
15245                .diagnostics_in_range(0..selection.start)
15246                .filter(|entry| entry.range.start <= selection.start),
15247        );
15248        let after = filtered(
15249            snapshot,
15250            severity,
15251            buffer
15252                .diagnostics_in_range(selection.start..buffer.len())
15253                .filter(|entry| entry.range.start >= selection.start),
15254        );
15255
15256        let mut found: Option<DiagnosticEntry<usize>> = None;
15257        if direction == Direction::Prev {
15258            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15259            {
15260                for diagnostic in prev_diagnostics.into_iter().rev() {
15261                    if diagnostic.range.start != selection.start
15262                        || active_group_id
15263                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15264                    {
15265                        found = Some(diagnostic);
15266                        break 'outer;
15267                    }
15268                }
15269            }
15270        } else {
15271            for diagnostic in after.chain(before) {
15272                if diagnostic.range.start != selection.start
15273                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15274                {
15275                    found = Some(diagnostic);
15276                    break;
15277                }
15278            }
15279        }
15280        let Some(next_diagnostic) = found else {
15281            return;
15282        };
15283
15284        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15285            return;
15286        };
15287        self.change_selections(Default::default(), window, cx, |s| {
15288            s.select_ranges(vec![
15289                next_diagnostic.range.start..next_diagnostic.range.start,
15290            ])
15291        });
15292        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15293        self.refresh_inline_completion(false, true, window, cx);
15294    }
15295
15296    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15298        let snapshot = self.snapshot(window, cx);
15299        let selection = self.selections.newest::<Point>(cx);
15300        self.go_to_hunk_before_or_after_position(
15301            &snapshot,
15302            selection.head(),
15303            Direction::Next,
15304            window,
15305            cx,
15306        );
15307    }
15308
15309    pub fn go_to_hunk_before_or_after_position(
15310        &mut self,
15311        snapshot: &EditorSnapshot,
15312        position: Point,
15313        direction: Direction,
15314        window: &mut Window,
15315        cx: &mut Context<Editor>,
15316    ) {
15317        let row = if direction == Direction::Next {
15318            self.hunk_after_position(snapshot, position)
15319                .map(|hunk| hunk.row_range.start)
15320        } else {
15321            self.hunk_before_position(snapshot, position)
15322        };
15323
15324        if let Some(row) = row {
15325            let destination = Point::new(row.0, 0);
15326            let autoscroll = Autoscroll::center();
15327
15328            self.unfold_ranges(&[destination..destination], false, false, cx);
15329            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15330                s.select_ranges([destination..destination]);
15331            });
15332        }
15333    }
15334
15335    fn hunk_after_position(
15336        &mut self,
15337        snapshot: &EditorSnapshot,
15338        position: Point,
15339    ) -> Option<MultiBufferDiffHunk> {
15340        snapshot
15341            .buffer_snapshot
15342            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15343            .find(|hunk| hunk.row_range.start.0 > position.row)
15344            .or_else(|| {
15345                snapshot
15346                    .buffer_snapshot
15347                    .diff_hunks_in_range(Point::zero()..position)
15348                    .find(|hunk| hunk.row_range.end.0 < position.row)
15349            })
15350    }
15351
15352    fn go_to_prev_hunk(
15353        &mut self,
15354        _: &GoToPreviousHunk,
15355        window: &mut Window,
15356        cx: &mut Context<Self>,
15357    ) {
15358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15359        let snapshot = self.snapshot(window, cx);
15360        let selection = self.selections.newest::<Point>(cx);
15361        self.go_to_hunk_before_or_after_position(
15362            &snapshot,
15363            selection.head(),
15364            Direction::Prev,
15365            window,
15366            cx,
15367        );
15368    }
15369
15370    fn hunk_before_position(
15371        &mut self,
15372        snapshot: &EditorSnapshot,
15373        position: Point,
15374    ) -> Option<MultiBufferRow> {
15375        snapshot
15376            .buffer_snapshot
15377            .diff_hunk_before(position)
15378            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15379    }
15380
15381    fn go_to_next_change(
15382        &mut self,
15383        _: &GoToNextChange,
15384        window: &mut Window,
15385        cx: &mut Context<Self>,
15386    ) {
15387        if let Some(selections) = self
15388            .change_list
15389            .next_change(1, Direction::Next)
15390            .map(|s| s.to_vec())
15391        {
15392            self.change_selections(Default::default(), window, cx, |s| {
15393                let map = s.display_map();
15394                s.select_display_ranges(selections.iter().map(|a| {
15395                    let point = a.to_display_point(&map);
15396                    point..point
15397                }))
15398            })
15399        }
15400    }
15401
15402    fn go_to_previous_change(
15403        &mut self,
15404        _: &GoToPreviousChange,
15405        window: &mut Window,
15406        cx: &mut Context<Self>,
15407    ) {
15408        if let Some(selections) = self
15409            .change_list
15410            .next_change(1, Direction::Prev)
15411            .map(|s| s.to_vec())
15412        {
15413            self.change_selections(Default::default(), window, cx, |s| {
15414                let map = s.display_map();
15415                s.select_display_ranges(selections.iter().map(|a| {
15416                    let point = a.to_display_point(&map);
15417                    point..point
15418                }))
15419            })
15420        }
15421    }
15422
15423    fn go_to_line<T: 'static>(
15424        &mut self,
15425        position: Anchor,
15426        highlight_color: Option<Hsla>,
15427        window: &mut Window,
15428        cx: &mut Context<Self>,
15429    ) {
15430        let snapshot = self.snapshot(window, cx).display_snapshot;
15431        let position = position.to_point(&snapshot.buffer_snapshot);
15432        let start = snapshot
15433            .buffer_snapshot
15434            .clip_point(Point::new(position.row, 0), Bias::Left);
15435        let end = start + Point::new(1, 0);
15436        let start = snapshot.buffer_snapshot.anchor_before(start);
15437        let end = snapshot.buffer_snapshot.anchor_before(end);
15438
15439        self.highlight_rows::<T>(
15440            start..end,
15441            highlight_color
15442                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15443            Default::default(),
15444            cx,
15445        );
15446
15447        if self.buffer.read(cx).is_singleton() {
15448            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15449        }
15450    }
15451
15452    pub fn go_to_definition(
15453        &mut self,
15454        _: &GoToDefinition,
15455        window: &mut Window,
15456        cx: &mut Context<Self>,
15457    ) -> Task<Result<Navigated>> {
15458        let definition =
15459            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15460        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15461        cx.spawn_in(window, async move |editor, cx| {
15462            if definition.await? == Navigated::Yes {
15463                return Ok(Navigated::Yes);
15464            }
15465            match fallback_strategy {
15466                GoToDefinitionFallback::None => Ok(Navigated::No),
15467                GoToDefinitionFallback::FindAllReferences => {
15468                    match editor.update_in(cx, |editor, window, cx| {
15469                        editor.find_all_references(&FindAllReferences, window, cx)
15470                    })? {
15471                        Some(references) => references.await,
15472                        None => Ok(Navigated::No),
15473                    }
15474                }
15475            }
15476        })
15477    }
15478
15479    pub fn go_to_declaration(
15480        &mut self,
15481        _: &GoToDeclaration,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) -> Task<Result<Navigated>> {
15485        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15486    }
15487
15488    pub fn go_to_declaration_split(
15489        &mut self,
15490        _: &GoToDeclaration,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) -> Task<Result<Navigated>> {
15494        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15495    }
15496
15497    pub fn go_to_implementation(
15498        &mut self,
15499        _: &GoToImplementation,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) -> Task<Result<Navigated>> {
15503        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15504    }
15505
15506    pub fn go_to_implementation_split(
15507        &mut self,
15508        _: &GoToImplementationSplit,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) -> Task<Result<Navigated>> {
15512        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15513    }
15514
15515    pub fn go_to_type_definition(
15516        &mut self,
15517        _: &GoToTypeDefinition,
15518        window: &mut Window,
15519        cx: &mut Context<Self>,
15520    ) -> Task<Result<Navigated>> {
15521        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15522    }
15523
15524    pub fn go_to_definition_split(
15525        &mut self,
15526        _: &GoToDefinitionSplit,
15527        window: &mut Window,
15528        cx: &mut Context<Self>,
15529    ) -> Task<Result<Navigated>> {
15530        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15531    }
15532
15533    pub fn go_to_type_definition_split(
15534        &mut self,
15535        _: &GoToTypeDefinitionSplit,
15536        window: &mut Window,
15537        cx: &mut Context<Self>,
15538    ) -> Task<Result<Navigated>> {
15539        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15540    }
15541
15542    fn go_to_definition_of_kind(
15543        &mut self,
15544        kind: GotoDefinitionKind,
15545        split: bool,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) -> Task<Result<Navigated>> {
15549        let Some(provider) = self.semantics_provider.clone() else {
15550            return Task::ready(Ok(Navigated::No));
15551        };
15552        let head = self.selections.newest::<usize>(cx).head();
15553        let buffer = self.buffer.read(cx);
15554        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15555            text_anchor
15556        } else {
15557            return Task::ready(Ok(Navigated::No));
15558        };
15559
15560        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15561            return Task::ready(Ok(Navigated::No));
15562        };
15563
15564        cx.spawn_in(window, async move |editor, cx| {
15565            let definitions = definitions.await?;
15566            let navigated = editor
15567                .update_in(cx, |editor, window, cx| {
15568                    editor.navigate_to_hover_links(
15569                        Some(kind),
15570                        definitions
15571                            .into_iter()
15572                            .filter(|location| {
15573                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15574                            })
15575                            .map(HoverLink::Text)
15576                            .collect::<Vec<_>>(),
15577                        split,
15578                        window,
15579                        cx,
15580                    )
15581                })?
15582                .await?;
15583            anyhow::Ok(navigated)
15584        })
15585    }
15586
15587    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15588        let selection = self.selections.newest_anchor();
15589        let head = selection.head();
15590        let tail = selection.tail();
15591
15592        let Some((buffer, start_position)) =
15593            self.buffer.read(cx).text_anchor_for_position(head, cx)
15594        else {
15595            return;
15596        };
15597
15598        let end_position = if head != tail {
15599            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15600                return;
15601            };
15602            Some(pos)
15603        } else {
15604            None
15605        };
15606
15607        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15608            let url = if let Some(end_pos) = end_position {
15609                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15610            } else {
15611                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15612            };
15613
15614            if let Some(url) = url {
15615                editor.update(cx, |_, cx| {
15616                    cx.open_url(&url);
15617                })
15618            } else {
15619                Ok(())
15620            }
15621        });
15622
15623        url_finder.detach();
15624    }
15625
15626    pub fn open_selected_filename(
15627        &mut self,
15628        _: &OpenSelectedFilename,
15629        window: &mut Window,
15630        cx: &mut Context<Self>,
15631    ) {
15632        let Some(workspace) = self.workspace() else {
15633            return;
15634        };
15635
15636        let position = self.selections.newest_anchor().head();
15637
15638        let Some((buffer, buffer_position)) =
15639            self.buffer.read(cx).text_anchor_for_position(position, cx)
15640        else {
15641            return;
15642        };
15643
15644        let project = self.project.clone();
15645
15646        cx.spawn_in(window, async move |_, cx| {
15647            let result = find_file(&buffer, project, buffer_position, cx).await;
15648
15649            if let Some((_, path)) = result {
15650                workspace
15651                    .update_in(cx, |workspace, window, cx| {
15652                        workspace.open_resolved_path(path, window, cx)
15653                    })?
15654                    .await?;
15655            }
15656            anyhow::Ok(())
15657        })
15658        .detach();
15659    }
15660
15661    pub(crate) fn navigate_to_hover_links(
15662        &mut self,
15663        kind: Option<GotoDefinitionKind>,
15664        mut definitions: Vec<HoverLink>,
15665        split: bool,
15666        window: &mut Window,
15667        cx: &mut Context<Editor>,
15668    ) -> Task<Result<Navigated>> {
15669        // If there is one definition, just open it directly
15670        if definitions.len() == 1 {
15671            let definition = definitions.pop().unwrap();
15672
15673            enum TargetTaskResult {
15674                Location(Option<Location>),
15675                AlreadyNavigated,
15676            }
15677
15678            let target_task = match definition {
15679                HoverLink::Text(link) => {
15680                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15681                }
15682                HoverLink::InlayHint(lsp_location, server_id) => {
15683                    let computation =
15684                        self.compute_target_location(lsp_location, server_id, window, cx);
15685                    cx.background_spawn(async move {
15686                        let location = computation.await?;
15687                        Ok(TargetTaskResult::Location(location))
15688                    })
15689                }
15690                HoverLink::Url(url) => {
15691                    cx.open_url(&url);
15692                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15693                }
15694                HoverLink::File(path) => {
15695                    if let Some(workspace) = self.workspace() {
15696                        cx.spawn_in(window, async move |_, cx| {
15697                            workspace
15698                                .update_in(cx, |workspace, window, cx| {
15699                                    workspace.open_resolved_path(path, window, cx)
15700                                })?
15701                                .await
15702                                .map(|_| TargetTaskResult::AlreadyNavigated)
15703                        })
15704                    } else {
15705                        Task::ready(Ok(TargetTaskResult::Location(None)))
15706                    }
15707                }
15708            };
15709            cx.spawn_in(window, async move |editor, cx| {
15710                let target = match target_task.await.context("target resolution task")? {
15711                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15712                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15713                    TargetTaskResult::Location(Some(target)) => target,
15714                };
15715
15716                editor.update_in(cx, |editor, window, cx| {
15717                    let Some(workspace) = editor.workspace() else {
15718                        return Navigated::No;
15719                    };
15720                    let pane = workspace.read(cx).active_pane().clone();
15721
15722                    let range = target.range.to_point(target.buffer.read(cx));
15723                    let range = editor.range_for_match(&range);
15724                    let range = collapse_multiline_range(range);
15725
15726                    if !split
15727                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15728                    {
15729                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15730                    } else {
15731                        window.defer(cx, move |window, cx| {
15732                            let target_editor: Entity<Self> =
15733                                workspace.update(cx, |workspace, cx| {
15734                                    let pane = if split {
15735                                        workspace.adjacent_pane(window, cx)
15736                                    } else {
15737                                        workspace.active_pane().clone()
15738                                    };
15739
15740                                    workspace.open_project_item(
15741                                        pane,
15742                                        target.buffer.clone(),
15743                                        true,
15744                                        true,
15745                                        window,
15746                                        cx,
15747                                    )
15748                                });
15749                            target_editor.update(cx, |target_editor, cx| {
15750                                // When selecting a definition in a different buffer, disable the nav history
15751                                // to avoid creating a history entry at the previous cursor location.
15752                                pane.update(cx, |pane, _| pane.disable_history());
15753                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15754                                pane.update(cx, |pane, _| pane.enable_history());
15755                            });
15756                        });
15757                    }
15758                    Navigated::Yes
15759                })
15760            })
15761        } else if !definitions.is_empty() {
15762            cx.spawn_in(window, async move |editor, cx| {
15763                let (title, location_tasks, workspace) = editor
15764                    .update_in(cx, |editor, window, cx| {
15765                        let tab_kind = match kind {
15766                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15767                            _ => "Definitions",
15768                        };
15769                        let title = definitions
15770                            .iter()
15771                            .find_map(|definition| match definition {
15772                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15773                                    let buffer = origin.buffer.read(cx);
15774                                    format!(
15775                                        "{} for {}",
15776                                        tab_kind,
15777                                        buffer
15778                                            .text_for_range(origin.range.clone())
15779                                            .collect::<String>()
15780                                    )
15781                                }),
15782                                HoverLink::InlayHint(_, _) => None,
15783                                HoverLink::Url(_) => None,
15784                                HoverLink::File(_) => None,
15785                            })
15786                            .unwrap_or(tab_kind.to_string());
15787                        let location_tasks = definitions
15788                            .into_iter()
15789                            .map(|definition| match definition {
15790                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15791                                HoverLink::InlayHint(lsp_location, server_id) => editor
15792                                    .compute_target_location(lsp_location, server_id, window, cx),
15793                                HoverLink::Url(_) => Task::ready(Ok(None)),
15794                                HoverLink::File(_) => Task::ready(Ok(None)),
15795                            })
15796                            .collect::<Vec<_>>();
15797                        (title, location_tasks, editor.workspace().clone())
15798                    })
15799                    .context("location tasks preparation")?;
15800
15801                let locations: Vec<Location> = future::join_all(location_tasks)
15802                    .await
15803                    .into_iter()
15804                    .filter_map(|location| location.transpose())
15805                    .collect::<Result<_>>()
15806                    .context("location tasks")?;
15807
15808                if locations.is_empty() {
15809                    return Ok(Navigated::No);
15810                }
15811
15812                let Some(workspace) = workspace else {
15813                    return Ok(Navigated::No);
15814                };
15815
15816                let opened = workspace
15817                    .update_in(cx, |workspace, window, cx| {
15818                        Self::open_locations_in_multibuffer(
15819                            workspace,
15820                            locations,
15821                            title,
15822                            split,
15823                            MultibufferSelectionMode::First,
15824                            window,
15825                            cx,
15826                        )
15827                    })
15828                    .ok();
15829
15830                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15831            })
15832        } else {
15833            Task::ready(Ok(Navigated::No))
15834        }
15835    }
15836
15837    fn compute_target_location(
15838        &self,
15839        lsp_location: lsp::Location,
15840        server_id: LanguageServerId,
15841        window: &mut Window,
15842        cx: &mut Context<Self>,
15843    ) -> Task<anyhow::Result<Option<Location>>> {
15844        let Some(project) = self.project.clone() else {
15845            return Task::ready(Ok(None));
15846        };
15847
15848        cx.spawn_in(window, async move |editor, cx| {
15849            let location_task = editor.update(cx, |_, cx| {
15850                project.update(cx, |project, cx| {
15851                    let language_server_name = project
15852                        .language_server_statuses(cx)
15853                        .find(|(id, _)| server_id == *id)
15854                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15855                    language_server_name.map(|language_server_name| {
15856                        project.open_local_buffer_via_lsp(
15857                            lsp_location.uri.clone(),
15858                            server_id,
15859                            language_server_name,
15860                            cx,
15861                        )
15862                    })
15863                })
15864            })?;
15865            let location = match location_task {
15866                Some(task) => Some({
15867                    let target_buffer_handle = task.await.context("open local buffer")?;
15868                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15869                        let target_start = target_buffer
15870                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15871                        let target_end = target_buffer
15872                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15873                        target_buffer.anchor_after(target_start)
15874                            ..target_buffer.anchor_before(target_end)
15875                    })?;
15876                    Location {
15877                        buffer: target_buffer_handle,
15878                        range,
15879                    }
15880                }),
15881                None => None,
15882            };
15883            Ok(location)
15884        })
15885    }
15886
15887    pub fn find_all_references(
15888        &mut self,
15889        _: &FindAllReferences,
15890        window: &mut Window,
15891        cx: &mut Context<Self>,
15892    ) -> Option<Task<Result<Navigated>>> {
15893        let selection = self.selections.newest::<usize>(cx);
15894        let multi_buffer = self.buffer.read(cx);
15895        let head = selection.head();
15896
15897        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15898        let head_anchor = multi_buffer_snapshot.anchor_at(
15899            head,
15900            if head < selection.tail() {
15901                Bias::Right
15902            } else {
15903                Bias::Left
15904            },
15905        );
15906
15907        match self
15908            .find_all_references_task_sources
15909            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15910        {
15911            Ok(_) => {
15912                log::info!(
15913                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15914                );
15915                return None;
15916            }
15917            Err(i) => {
15918                self.find_all_references_task_sources.insert(i, head_anchor);
15919            }
15920        }
15921
15922        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15923        let workspace = self.workspace()?;
15924        let project = workspace.read(cx).project().clone();
15925        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15926        Some(cx.spawn_in(window, async move |editor, cx| {
15927            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15928                if let Ok(i) = editor
15929                    .find_all_references_task_sources
15930                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15931                {
15932                    editor.find_all_references_task_sources.remove(i);
15933                }
15934            });
15935
15936            let locations = references.await?;
15937            if locations.is_empty() {
15938                return anyhow::Ok(Navigated::No);
15939            }
15940
15941            workspace.update_in(cx, |workspace, window, cx| {
15942                let title = locations
15943                    .first()
15944                    .as_ref()
15945                    .map(|location| {
15946                        let buffer = location.buffer.read(cx);
15947                        format!(
15948                            "References to `{}`",
15949                            buffer
15950                                .text_for_range(location.range.clone())
15951                                .collect::<String>()
15952                        )
15953                    })
15954                    .unwrap();
15955                Self::open_locations_in_multibuffer(
15956                    workspace,
15957                    locations,
15958                    title,
15959                    false,
15960                    MultibufferSelectionMode::First,
15961                    window,
15962                    cx,
15963                );
15964                Navigated::Yes
15965            })
15966        }))
15967    }
15968
15969    /// Opens a multibuffer with the given project locations in it
15970    pub fn open_locations_in_multibuffer(
15971        workspace: &mut Workspace,
15972        mut locations: Vec<Location>,
15973        title: String,
15974        split: bool,
15975        multibuffer_selection_mode: MultibufferSelectionMode,
15976        window: &mut Window,
15977        cx: &mut Context<Workspace>,
15978    ) {
15979        if locations.is_empty() {
15980            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15981            return;
15982        }
15983
15984        // If there are multiple definitions, open them in a multibuffer
15985        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15986        let mut locations = locations.into_iter().peekable();
15987        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15988        let capability = workspace.project().read(cx).capability();
15989
15990        let excerpt_buffer = cx.new(|cx| {
15991            let mut multibuffer = MultiBuffer::new(capability);
15992            while let Some(location) = locations.next() {
15993                let buffer = location.buffer.read(cx);
15994                let mut ranges_for_buffer = Vec::new();
15995                let range = location.range.to_point(buffer);
15996                ranges_for_buffer.push(range.clone());
15997
15998                while let Some(next_location) = locations.peek() {
15999                    if next_location.buffer == location.buffer {
16000                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16001                        locations.next();
16002                    } else {
16003                        break;
16004                    }
16005                }
16006
16007                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16008                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16009                    PathKey::for_buffer(&location.buffer, cx),
16010                    location.buffer.clone(),
16011                    ranges_for_buffer,
16012                    DEFAULT_MULTIBUFFER_CONTEXT,
16013                    cx,
16014                );
16015                ranges.extend(new_ranges)
16016            }
16017
16018            multibuffer.with_title(title)
16019        });
16020
16021        let editor = cx.new(|cx| {
16022            Editor::for_multibuffer(
16023                excerpt_buffer,
16024                Some(workspace.project().clone()),
16025                window,
16026                cx,
16027            )
16028        });
16029        editor.update(cx, |editor, cx| {
16030            match multibuffer_selection_mode {
16031                MultibufferSelectionMode::First => {
16032                    if let Some(first_range) = ranges.first() {
16033                        editor.change_selections(
16034                            SelectionEffects::no_scroll(),
16035                            window,
16036                            cx,
16037                            |selections| {
16038                                selections.clear_disjoint();
16039                                selections
16040                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16041                            },
16042                        );
16043                    }
16044                    editor.highlight_background::<Self>(
16045                        &ranges,
16046                        |theme| theme.colors().editor_highlighted_line_background,
16047                        cx,
16048                    );
16049                }
16050                MultibufferSelectionMode::All => {
16051                    editor.change_selections(
16052                        SelectionEffects::no_scroll(),
16053                        window,
16054                        cx,
16055                        |selections| {
16056                            selections.clear_disjoint();
16057                            selections.select_anchor_ranges(ranges);
16058                        },
16059                    );
16060                }
16061            }
16062            editor.register_buffers_with_language_servers(cx);
16063        });
16064
16065        let item = Box::new(editor);
16066        let item_id = item.item_id();
16067
16068        if split {
16069            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16070        } else {
16071            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16072                let (preview_item_id, preview_item_idx) =
16073                    workspace.active_pane().read_with(cx, |pane, _| {
16074                        (pane.preview_item_id(), pane.preview_item_idx())
16075                    });
16076
16077                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16078
16079                if let Some(preview_item_id) = preview_item_id {
16080                    workspace.active_pane().update(cx, |pane, cx| {
16081                        pane.remove_item(preview_item_id, false, false, window, cx);
16082                    });
16083                }
16084            } else {
16085                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16086            }
16087        }
16088        workspace.active_pane().update(cx, |pane, cx| {
16089            pane.set_preview_item_id(Some(item_id), cx);
16090        });
16091    }
16092
16093    pub fn rename(
16094        &mut self,
16095        _: &Rename,
16096        window: &mut Window,
16097        cx: &mut Context<Self>,
16098    ) -> Option<Task<Result<()>>> {
16099        use language::ToOffset as _;
16100
16101        let provider = self.semantics_provider.clone()?;
16102        let selection = self.selections.newest_anchor().clone();
16103        let (cursor_buffer, cursor_buffer_position) = self
16104            .buffer
16105            .read(cx)
16106            .text_anchor_for_position(selection.head(), cx)?;
16107        let (tail_buffer, cursor_buffer_position_end) = self
16108            .buffer
16109            .read(cx)
16110            .text_anchor_for_position(selection.tail(), cx)?;
16111        if tail_buffer != cursor_buffer {
16112            return None;
16113        }
16114
16115        let snapshot = cursor_buffer.read(cx).snapshot();
16116        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16117        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16118        let prepare_rename = provider
16119            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16120            .unwrap_or_else(|| Task::ready(Ok(None)));
16121        drop(snapshot);
16122
16123        Some(cx.spawn_in(window, async move |this, cx| {
16124            let rename_range = if let Some(range) = prepare_rename.await? {
16125                Some(range)
16126            } else {
16127                this.update(cx, |this, cx| {
16128                    let buffer = this.buffer.read(cx).snapshot(cx);
16129                    let mut buffer_highlights = this
16130                        .document_highlights_for_position(selection.head(), &buffer)
16131                        .filter(|highlight| {
16132                            highlight.start.excerpt_id == selection.head().excerpt_id
16133                                && highlight.end.excerpt_id == selection.head().excerpt_id
16134                        });
16135                    buffer_highlights
16136                        .next()
16137                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16138                })?
16139            };
16140            if let Some(rename_range) = rename_range {
16141                this.update_in(cx, |this, window, cx| {
16142                    let snapshot = cursor_buffer.read(cx).snapshot();
16143                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16144                    let cursor_offset_in_rename_range =
16145                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16146                    let cursor_offset_in_rename_range_end =
16147                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16148
16149                    this.take_rename(false, window, cx);
16150                    let buffer = this.buffer.read(cx).read(cx);
16151                    let cursor_offset = selection.head().to_offset(&buffer);
16152                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16153                    let rename_end = rename_start + rename_buffer_range.len();
16154                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16155                    let mut old_highlight_id = None;
16156                    let old_name: Arc<str> = buffer
16157                        .chunks(rename_start..rename_end, true)
16158                        .map(|chunk| {
16159                            if old_highlight_id.is_none() {
16160                                old_highlight_id = chunk.syntax_highlight_id;
16161                            }
16162                            chunk.text
16163                        })
16164                        .collect::<String>()
16165                        .into();
16166
16167                    drop(buffer);
16168
16169                    // Position the selection in the rename editor so that it matches the current selection.
16170                    this.show_local_selections = false;
16171                    let rename_editor = cx.new(|cx| {
16172                        let mut editor = Editor::single_line(window, cx);
16173                        editor.buffer.update(cx, |buffer, cx| {
16174                            buffer.edit([(0..0, old_name.clone())], None, cx)
16175                        });
16176                        let rename_selection_range = match cursor_offset_in_rename_range
16177                            .cmp(&cursor_offset_in_rename_range_end)
16178                        {
16179                            Ordering::Equal => {
16180                                editor.select_all(&SelectAll, window, cx);
16181                                return editor;
16182                            }
16183                            Ordering::Less => {
16184                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16185                            }
16186                            Ordering::Greater => {
16187                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16188                            }
16189                        };
16190                        if rename_selection_range.end > old_name.len() {
16191                            editor.select_all(&SelectAll, window, cx);
16192                        } else {
16193                            editor.change_selections(Default::default(), window, cx, |s| {
16194                                s.select_ranges([rename_selection_range]);
16195                            });
16196                        }
16197                        editor
16198                    });
16199                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16200                        if e == &EditorEvent::Focused {
16201                            cx.emit(EditorEvent::FocusedIn)
16202                        }
16203                    })
16204                    .detach();
16205
16206                    let write_highlights =
16207                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16208                    let read_highlights =
16209                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16210                    let ranges = write_highlights
16211                        .iter()
16212                        .flat_map(|(_, ranges)| ranges.iter())
16213                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16214                        .cloned()
16215                        .collect();
16216
16217                    this.highlight_text::<Rename>(
16218                        ranges,
16219                        HighlightStyle {
16220                            fade_out: Some(0.6),
16221                            ..Default::default()
16222                        },
16223                        cx,
16224                    );
16225                    let rename_focus_handle = rename_editor.focus_handle(cx);
16226                    window.focus(&rename_focus_handle);
16227                    let block_id = this.insert_blocks(
16228                        [BlockProperties {
16229                            style: BlockStyle::Flex,
16230                            placement: BlockPlacement::Below(range.start),
16231                            height: Some(1),
16232                            render: Arc::new({
16233                                let rename_editor = rename_editor.clone();
16234                                move |cx: &mut BlockContext| {
16235                                    let mut text_style = cx.editor_style.text.clone();
16236                                    if let Some(highlight_style) = old_highlight_id
16237                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16238                                    {
16239                                        text_style = text_style.highlight(highlight_style);
16240                                    }
16241                                    div()
16242                                        .block_mouse_except_scroll()
16243                                        .pl(cx.anchor_x)
16244                                        .child(EditorElement::new(
16245                                            &rename_editor,
16246                                            EditorStyle {
16247                                                background: cx.theme().system().transparent,
16248                                                local_player: cx.editor_style.local_player,
16249                                                text: text_style,
16250                                                scrollbar_width: cx.editor_style.scrollbar_width,
16251                                                syntax: cx.editor_style.syntax.clone(),
16252                                                status: cx.editor_style.status.clone(),
16253                                                inlay_hints_style: HighlightStyle {
16254                                                    font_weight: Some(FontWeight::BOLD),
16255                                                    ..make_inlay_hints_style(cx.app)
16256                                                },
16257                                                inline_completion_styles: make_suggestion_styles(
16258                                                    cx.app,
16259                                                ),
16260                                                ..EditorStyle::default()
16261                                            },
16262                                        ))
16263                                        .into_any_element()
16264                                }
16265                            }),
16266                            priority: 0,
16267                        }],
16268                        Some(Autoscroll::fit()),
16269                        cx,
16270                    )[0];
16271                    this.pending_rename = Some(RenameState {
16272                        range,
16273                        old_name,
16274                        editor: rename_editor,
16275                        block_id,
16276                    });
16277                })?;
16278            }
16279
16280            Ok(())
16281        }))
16282    }
16283
16284    pub fn confirm_rename(
16285        &mut self,
16286        _: &ConfirmRename,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) -> Option<Task<Result<()>>> {
16290        let rename = self.take_rename(false, window, cx)?;
16291        let workspace = self.workspace()?.downgrade();
16292        let (buffer, start) = self
16293            .buffer
16294            .read(cx)
16295            .text_anchor_for_position(rename.range.start, cx)?;
16296        let (end_buffer, _) = self
16297            .buffer
16298            .read(cx)
16299            .text_anchor_for_position(rename.range.end, cx)?;
16300        if buffer != end_buffer {
16301            return None;
16302        }
16303
16304        let old_name = rename.old_name;
16305        let new_name = rename.editor.read(cx).text(cx);
16306
16307        let rename = self.semantics_provider.as_ref()?.perform_rename(
16308            &buffer,
16309            start,
16310            new_name.clone(),
16311            cx,
16312        )?;
16313
16314        Some(cx.spawn_in(window, async move |editor, cx| {
16315            let project_transaction = rename.await?;
16316            Self::open_project_transaction(
16317                &editor,
16318                workspace,
16319                project_transaction,
16320                format!("Rename: {}{}", old_name, new_name),
16321                cx,
16322            )
16323            .await?;
16324
16325            editor.update(cx, |editor, cx| {
16326                editor.refresh_document_highlights(cx);
16327            })?;
16328            Ok(())
16329        }))
16330    }
16331
16332    fn take_rename(
16333        &mut self,
16334        moving_cursor: bool,
16335        window: &mut Window,
16336        cx: &mut Context<Self>,
16337    ) -> Option<RenameState> {
16338        let rename = self.pending_rename.take()?;
16339        if rename.editor.focus_handle(cx).is_focused(window) {
16340            window.focus(&self.focus_handle);
16341        }
16342
16343        self.remove_blocks(
16344            [rename.block_id].into_iter().collect(),
16345            Some(Autoscroll::fit()),
16346            cx,
16347        );
16348        self.clear_highlights::<Rename>(cx);
16349        self.show_local_selections = true;
16350
16351        if moving_cursor {
16352            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16353                editor.selections.newest::<usize>(cx).head()
16354            });
16355
16356            // Update the selection to match the position of the selection inside
16357            // the rename editor.
16358            let snapshot = self.buffer.read(cx).read(cx);
16359            let rename_range = rename.range.to_offset(&snapshot);
16360            let cursor_in_editor = snapshot
16361                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16362                .min(rename_range.end);
16363            drop(snapshot);
16364
16365            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16366                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16367            });
16368        } else {
16369            self.refresh_document_highlights(cx);
16370        }
16371
16372        Some(rename)
16373    }
16374
16375    pub fn pending_rename(&self) -> Option<&RenameState> {
16376        self.pending_rename.as_ref()
16377    }
16378
16379    fn format(
16380        &mut self,
16381        _: &Format,
16382        window: &mut Window,
16383        cx: &mut Context<Self>,
16384    ) -> Option<Task<Result<()>>> {
16385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16386
16387        let project = match &self.project {
16388            Some(project) => project.clone(),
16389            None => return None,
16390        };
16391
16392        Some(self.perform_format(
16393            project,
16394            FormatTrigger::Manual,
16395            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16396            window,
16397            cx,
16398        ))
16399    }
16400
16401    fn format_selections(
16402        &mut self,
16403        _: &FormatSelections,
16404        window: &mut Window,
16405        cx: &mut Context<Self>,
16406    ) -> Option<Task<Result<()>>> {
16407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16408
16409        let project = match &self.project {
16410            Some(project) => project.clone(),
16411            None => return None,
16412        };
16413
16414        let ranges = self
16415            .selections
16416            .all_adjusted(cx)
16417            .into_iter()
16418            .map(|selection| selection.range())
16419            .collect_vec();
16420
16421        Some(self.perform_format(
16422            project,
16423            FormatTrigger::Manual,
16424            FormatTarget::Ranges(ranges),
16425            window,
16426            cx,
16427        ))
16428    }
16429
16430    fn perform_format(
16431        &mut self,
16432        project: Entity<Project>,
16433        trigger: FormatTrigger,
16434        target: FormatTarget,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) -> Task<Result<()>> {
16438        let buffer = self.buffer.clone();
16439        let (buffers, target) = match target {
16440            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16441            FormatTarget::Ranges(selection_ranges) => {
16442                let multi_buffer = buffer.read(cx);
16443                let snapshot = multi_buffer.read(cx);
16444                let mut buffers = HashSet::default();
16445                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16446                    BTreeMap::new();
16447                for selection_range in selection_ranges {
16448                    for (buffer, buffer_range, _) in
16449                        snapshot.range_to_buffer_ranges(selection_range)
16450                    {
16451                        let buffer_id = buffer.remote_id();
16452                        let start = buffer.anchor_before(buffer_range.start);
16453                        let end = buffer.anchor_after(buffer_range.end);
16454                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16455                        buffer_id_to_ranges
16456                            .entry(buffer_id)
16457                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16458                            .or_insert_with(|| vec![start..end]);
16459                    }
16460                }
16461                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16462            }
16463        };
16464
16465        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16466        let selections_prev = transaction_id_prev
16467            .and_then(|transaction_id_prev| {
16468                // default to selections as they were after the last edit, if we have them,
16469                // instead of how they are now.
16470                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16471                // will take you back to where you made the last edit, instead of staying where you scrolled
16472                self.selection_history
16473                    .transaction(transaction_id_prev)
16474                    .map(|t| t.0.clone())
16475            })
16476            .unwrap_or_else(|| {
16477                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16478                self.selections.disjoint_anchors()
16479            });
16480
16481        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16482        let format = project.update(cx, |project, cx| {
16483            project.format(buffers, target, true, trigger, cx)
16484        });
16485
16486        cx.spawn_in(window, async move |editor, cx| {
16487            let transaction = futures::select_biased! {
16488                transaction = format.log_err().fuse() => transaction,
16489                () = timeout => {
16490                    log::warn!("timed out waiting for formatting");
16491                    None
16492                }
16493            };
16494
16495            buffer
16496                .update(cx, |buffer, cx| {
16497                    if let Some(transaction) = transaction {
16498                        if !buffer.is_singleton() {
16499                            buffer.push_transaction(&transaction.0, cx);
16500                        }
16501                    }
16502                    cx.notify();
16503                })
16504                .ok();
16505
16506            if let Some(transaction_id_now) =
16507                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16508            {
16509                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16510                if has_new_transaction {
16511                    _ = editor.update(cx, |editor, _| {
16512                        editor
16513                            .selection_history
16514                            .insert_transaction(transaction_id_now, selections_prev);
16515                    });
16516                }
16517            }
16518
16519            Ok(())
16520        })
16521    }
16522
16523    fn organize_imports(
16524        &mut self,
16525        _: &OrganizeImports,
16526        window: &mut Window,
16527        cx: &mut Context<Self>,
16528    ) -> Option<Task<Result<()>>> {
16529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16530        let project = match &self.project {
16531            Some(project) => project.clone(),
16532            None => return None,
16533        };
16534        Some(self.perform_code_action_kind(
16535            project,
16536            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16537            window,
16538            cx,
16539        ))
16540    }
16541
16542    fn perform_code_action_kind(
16543        &mut self,
16544        project: Entity<Project>,
16545        kind: CodeActionKind,
16546        window: &mut Window,
16547        cx: &mut Context<Self>,
16548    ) -> Task<Result<()>> {
16549        let buffer = self.buffer.clone();
16550        let buffers = buffer.read(cx).all_buffers();
16551        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16552        let apply_action = project.update(cx, |project, cx| {
16553            project.apply_code_action_kind(buffers, kind, true, cx)
16554        });
16555        cx.spawn_in(window, async move |_, cx| {
16556            let transaction = futures::select_biased! {
16557                () = timeout => {
16558                    log::warn!("timed out waiting for executing code action");
16559                    None
16560                }
16561                transaction = apply_action.log_err().fuse() => transaction,
16562            };
16563            buffer
16564                .update(cx, |buffer, cx| {
16565                    // check if we need this
16566                    if let Some(transaction) = transaction {
16567                        if !buffer.is_singleton() {
16568                            buffer.push_transaction(&transaction.0, cx);
16569                        }
16570                    }
16571                    cx.notify();
16572                })
16573                .ok();
16574            Ok(())
16575        })
16576    }
16577
16578    pub fn restart_language_server(
16579        &mut self,
16580        _: &RestartLanguageServer,
16581        _: &mut Window,
16582        cx: &mut Context<Self>,
16583    ) {
16584        if let Some(project) = self.project.clone() {
16585            self.buffer.update(cx, |multi_buffer, cx| {
16586                project.update(cx, |project, cx| {
16587                    project.restart_language_servers_for_buffers(
16588                        multi_buffer.all_buffers().into_iter().collect(),
16589                        HashSet::default(),
16590                        cx,
16591                    );
16592                });
16593            })
16594        }
16595    }
16596
16597    pub fn stop_language_server(
16598        &mut self,
16599        _: &StopLanguageServer,
16600        _: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        if let Some(project) = self.project.clone() {
16604            self.buffer.update(cx, |multi_buffer, cx| {
16605                project.update(cx, |project, cx| {
16606                    project.stop_language_servers_for_buffers(
16607                        multi_buffer.all_buffers().into_iter().collect(),
16608                        HashSet::default(),
16609                        cx,
16610                    );
16611                    cx.emit(project::Event::RefreshInlayHints);
16612                });
16613            });
16614        }
16615    }
16616
16617    fn cancel_language_server_work(
16618        workspace: &mut Workspace,
16619        _: &actions::CancelLanguageServerWork,
16620        _: &mut Window,
16621        cx: &mut Context<Workspace>,
16622    ) {
16623        let project = workspace.project();
16624        let buffers = workspace
16625            .active_item(cx)
16626            .and_then(|item| item.act_as::<Editor>(cx))
16627            .map_or(HashSet::default(), |editor| {
16628                editor.read(cx).buffer.read(cx).all_buffers()
16629            });
16630        project.update(cx, |project, cx| {
16631            project.cancel_language_server_work_for_buffers(buffers, cx);
16632        });
16633    }
16634
16635    fn show_character_palette(
16636        &mut self,
16637        _: &ShowCharacterPalette,
16638        window: &mut Window,
16639        _: &mut Context<Self>,
16640    ) {
16641        window.show_character_palette();
16642    }
16643
16644    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16645        if !self.diagnostics_enabled() {
16646            return;
16647        }
16648
16649        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16650            let buffer = self.buffer.read(cx).snapshot(cx);
16651            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16652            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16653            let is_valid = buffer
16654                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16655                .any(|entry| {
16656                    entry.diagnostic.is_primary
16657                        && !entry.range.is_empty()
16658                        && entry.range.start == primary_range_start
16659                        && entry.diagnostic.message == active_diagnostics.active_message
16660                });
16661
16662            if !is_valid {
16663                self.dismiss_diagnostics(cx);
16664            }
16665        }
16666    }
16667
16668    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16669        match &self.active_diagnostics {
16670            ActiveDiagnostic::Group(group) => Some(group),
16671            _ => None,
16672        }
16673    }
16674
16675    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16676        if !self.diagnostics_enabled() {
16677            return;
16678        }
16679        self.dismiss_diagnostics(cx);
16680        self.active_diagnostics = ActiveDiagnostic::All;
16681    }
16682
16683    fn activate_diagnostics(
16684        &mut self,
16685        buffer_id: BufferId,
16686        diagnostic: DiagnosticEntry<usize>,
16687        window: &mut Window,
16688        cx: &mut Context<Self>,
16689    ) {
16690        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16691            return;
16692        }
16693        self.dismiss_diagnostics(cx);
16694        let snapshot = self.snapshot(window, cx);
16695        let buffer = self.buffer.read(cx).snapshot(cx);
16696        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16697            return;
16698        };
16699
16700        let diagnostic_group = buffer
16701            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16702            .collect::<Vec<_>>();
16703
16704        let blocks =
16705            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16706
16707        let blocks = self.display_map.update(cx, |display_map, cx| {
16708            display_map.insert_blocks(blocks, cx).into_iter().collect()
16709        });
16710        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16711            active_range: buffer.anchor_before(diagnostic.range.start)
16712                ..buffer.anchor_after(diagnostic.range.end),
16713            active_message: diagnostic.diagnostic.message.clone(),
16714            group_id: diagnostic.diagnostic.group_id,
16715            blocks,
16716        });
16717        cx.notify();
16718    }
16719
16720    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16721        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16722            return;
16723        };
16724
16725        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16726        if let ActiveDiagnostic::Group(group) = prev {
16727            self.display_map.update(cx, |display_map, cx| {
16728                display_map.remove_blocks(group.blocks, cx);
16729            });
16730            cx.notify();
16731        }
16732    }
16733
16734    /// Disable inline diagnostics rendering for this editor.
16735    pub fn disable_inline_diagnostics(&mut self) {
16736        self.inline_diagnostics_enabled = false;
16737        self.inline_diagnostics_update = Task::ready(());
16738        self.inline_diagnostics.clear();
16739    }
16740
16741    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16742        self.diagnostics_enabled = false;
16743        self.dismiss_diagnostics(cx);
16744        self.inline_diagnostics_update = Task::ready(());
16745        self.inline_diagnostics.clear();
16746    }
16747
16748    pub fn diagnostics_enabled(&self) -> bool {
16749        self.diagnostics_enabled && self.mode.is_full()
16750    }
16751
16752    pub fn inline_diagnostics_enabled(&self) -> bool {
16753        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16754    }
16755
16756    pub fn show_inline_diagnostics(&self) -> bool {
16757        self.show_inline_diagnostics
16758    }
16759
16760    pub fn toggle_inline_diagnostics(
16761        &mut self,
16762        _: &ToggleInlineDiagnostics,
16763        window: &mut Window,
16764        cx: &mut Context<Editor>,
16765    ) {
16766        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16767        self.refresh_inline_diagnostics(false, window, cx);
16768    }
16769
16770    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16771        self.diagnostics_max_severity = severity;
16772        self.display_map.update(cx, |display_map, _| {
16773            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16774        });
16775    }
16776
16777    pub fn toggle_diagnostics(
16778        &mut self,
16779        _: &ToggleDiagnostics,
16780        window: &mut Window,
16781        cx: &mut Context<Editor>,
16782    ) {
16783        if !self.diagnostics_enabled() {
16784            return;
16785        }
16786
16787        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16788            EditorSettings::get_global(cx)
16789                .diagnostics_max_severity
16790                .filter(|severity| severity != &DiagnosticSeverity::Off)
16791                .unwrap_or(DiagnosticSeverity::Hint)
16792        } else {
16793            DiagnosticSeverity::Off
16794        };
16795        self.set_max_diagnostics_severity(new_severity, cx);
16796        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16797            self.active_diagnostics = ActiveDiagnostic::None;
16798            self.inline_diagnostics_update = Task::ready(());
16799            self.inline_diagnostics.clear();
16800        } else {
16801            self.refresh_inline_diagnostics(false, window, cx);
16802        }
16803
16804        cx.notify();
16805    }
16806
16807    pub fn toggle_minimap(
16808        &mut self,
16809        _: &ToggleMinimap,
16810        window: &mut Window,
16811        cx: &mut Context<Editor>,
16812    ) {
16813        if self.supports_minimap(cx) {
16814            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16815        }
16816    }
16817
16818    fn refresh_inline_diagnostics(
16819        &mut self,
16820        debounce: bool,
16821        window: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) {
16824        let max_severity = ProjectSettings::get_global(cx)
16825            .diagnostics
16826            .inline
16827            .max_severity
16828            .unwrap_or(self.diagnostics_max_severity);
16829
16830        if !self.inline_diagnostics_enabled()
16831            || !self.show_inline_diagnostics
16832            || max_severity == DiagnosticSeverity::Off
16833        {
16834            self.inline_diagnostics_update = Task::ready(());
16835            self.inline_diagnostics.clear();
16836            return;
16837        }
16838
16839        let debounce_ms = ProjectSettings::get_global(cx)
16840            .diagnostics
16841            .inline
16842            .update_debounce_ms;
16843        let debounce = if debounce && debounce_ms > 0 {
16844            Some(Duration::from_millis(debounce_ms))
16845        } else {
16846            None
16847        };
16848        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16849            if let Some(debounce) = debounce {
16850                cx.background_executor().timer(debounce).await;
16851            }
16852            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16853                editor
16854                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16855                    .ok()
16856            }) else {
16857                return;
16858            };
16859
16860            let new_inline_diagnostics = cx
16861                .background_spawn(async move {
16862                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16863                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16864                        let message = diagnostic_entry
16865                            .diagnostic
16866                            .message
16867                            .split_once('\n')
16868                            .map(|(line, _)| line)
16869                            .map(SharedString::new)
16870                            .unwrap_or_else(|| {
16871                                SharedString::from(diagnostic_entry.diagnostic.message)
16872                            });
16873                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16874                        let (Ok(i) | Err(i)) = inline_diagnostics
16875                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16876                        inline_diagnostics.insert(
16877                            i,
16878                            (
16879                                start_anchor,
16880                                InlineDiagnostic {
16881                                    message,
16882                                    group_id: diagnostic_entry.diagnostic.group_id,
16883                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16884                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16885                                    severity: diagnostic_entry.diagnostic.severity,
16886                                },
16887                            ),
16888                        );
16889                    }
16890                    inline_diagnostics
16891                })
16892                .await;
16893
16894            editor
16895                .update(cx, |editor, cx| {
16896                    editor.inline_diagnostics = new_inline_diagnostics;
16897                    cx.notify();
16898                })
16899                .ok();
16900        });
16901    }
16902
16903    fn pull_diagnostics(
16904        &mut self,
16905        buffer_id: Option<BufferId>,
16906        window: &Window,
16907        cx: &mut Context<Self>,
16908    ) -> Option<()> {
16909        if !self.mode().is_full() {
16910            return None;
16911        }
16912        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16913            .diagnostics
16914            .lsp_pull_diagnostics;
16915        if !pull_diagnostics_settings.enabled {
16916            return None;
16917        }
16918        let project = self.project.as_ref()?.downgrade();
16919        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16920        let mut buffers = self.buffer.read(cx).all_buffers();
16921        if let Some(buffer_id) = buffer_id {
16922            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16923        }
16924
16925        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16926            cx.background_executor().timer(debounce).await;
16927
16928            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16929                buffers
16930                    .into_iter()
16931                    .filter_map(|buffer| {
16932                        project
16933                            .update(cx, |project, cx| {
16934                                project.lsp_store().update(cx, |lsp_store, cx| {
16935                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16936                                })
16937                            })
16938                            .ok()
16939                    })
16940                    .collect::<FuturesUnordered<_>>()
16941            }) else {
16942                return;
16943            };
16944
16945            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16946                match pull_task {
16947                    Ok(()) => {
16948                        if editor
16949                            .update_in(cx, |editor, window, cx| {
16950                                editor.update_diagnostics_state(window, cx);
16951                            })
16952                            .is_err()
16953                        {
16954                            return;
16955                        }
16956                    }
16957                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16958                }
16959            }
16960        });
16961
16962        Some(())
16963    }
16964
16965    pub fn set_selections_from_remote(
16966        &mut self,
16967        selections: Vec<Selection<Anchor>>,
16968        pending_selection: Option<Selection<Anchor>>,
16969        window: &mut Window,
16970        cx: &mut Context<Self>,
16971    ) {
16972        let old_cursor_position = self.selections.newest_anchor().head();
16973        self.selections.change_with(cx, |s| {
16974            s.select_anchors(selections);
16975            if let Some(pending_selection) = pending_selection {
16976                s.set_pending(pending_selection, SelectMode::Character);
16977            } else {
16978                s.clear_pending();
16979            }
16980        });
16981        self.selections_did_change(
16982            false,
16983            &old_cursor_position,
16984            SelectionEffects::default(),
16985            window,
16986            cx,
16987        );
16988    }
16989
16990    pub fn transact(
16991        &mut self,
16992        window: &mut Window,
16993        cx: &mut Context<Self>,
16994        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16995    ) -> Option<TransactionId> {
16996        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16997            this.start_transaction_at(Instant::now(), window, cx);
16998            update(this, window, cx);
16999            this.end_transaction_at(Instant::now(), cx)
17000        })
17001    }
17002
17003    pub fn start_transaction_at(
17004        &mut self,
17005        now: Instant,
17006        window: &mut Window,
17007        cx: &mut Context<Self>,
17008    ) -> Option<TransactionId> {
17009        self.end_selection(window, cx);
17010        if let Some(tx_id) = self
17011            .buffer
17012            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17013        {
17014            self.selection_history
17015                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17016            cx.emit(EditorEvent::TransactionBegun {
17017                transaction_id: tx_id,
17018            });
17019            Some(tx_id)
17020        } else {
17021            None
17022        }
17023    }
17024
17025    pub fn end_transaction_at(
17026        &mut self,
17027        now: Instant,
17028        cx: &mut Context<Self>,
17029    ) -> Option<TransactionId> {
17030        if let Some(transaction_id) = self
17031            .buffer
17032            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17033        {
17034            if let Some((_, end_selections)) =
17035                self.selection_history.transaction_mut(transaction_id)
17036            {
17037                *end_selections = Some(self.selections.disjoint_anchors());
17038            } else {
17039                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17040            }
17041
17042            cx.emit(EditorEvent::Edited { transaction_id });
17043            Some(transaction_id)
17044        } else {
17045            None
17046        }
17047    }
17048
17049    pub fn modify_transaction_selection_history(
17050        &mut self,
17051        transaction_id: TransactionId,
17052        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17053    ) -> bool {
17054        self.selection_history
17055            .transaction_mut(transaction_id)
17056            .map(modify)
17057            .is_some()
17058    }
17059
17060    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17061        if self.selection_mark_mode {
17062            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17063                s.move_with(|_, sel| {
17064                    sel.collapse_to(sel.head(), SelectionGoal::None);
17065                });
17066            })
17067        }
17068        self.selection_mark_mode = true;
17069        cx.notify();
17070    }
17071
17072    pub fn swap_selection_ends(
17073        &mut self,
17074        _: &actions::SwapSelectionEnds,
17075        window: &mut Window,
17076        cx: &mut Context<Self>,
17077    ) {
17078        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17079            s.move_with(|_, sel| {
17080                if sel.start != sel.end {
17081                    sel.reversed = !sel.reversed
17082                }
17083            });
17084        });
17085        self.request_autoscroll(Autoscroll::newest(), cx);
17086        cx.notify();
17087    }
17088
17089    pub fn toggle_focus(
17090        workspace: &mut Workspace,
17091        _: &actions::ToggleFocus,
17092        window: &mut Window,
17093        cx: &mut Context<Workspace>,
17094    ) {
17095        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17096            return;
17097        };
17098        workspace.activate_item(&item, true, true, window, cx);
17099    }
17100
17101    pub fn toggle_fold(
17102        &mut self,
17103        _: &actions::ToggleFold,
17104        window: &mut Window,
17105        cx: &mut Context<Self>,
17106    ) {
17107        if self.is_singleton(cx) {
17108            let selection = self.selections.newest::<Point>(cx);
17109
17110            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17111            let range = if selection.is_empty() {
17112                let point = selection.head().to_display_point(&display_map);
17113                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17114                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17115                    .to_point(&display_map);
17116                start..end
17117            } else {
17118                selection.range()
17119            };
17120            if display_map.folds_in_range(range).next().is_some() {
17121                self.unfold_lines(&Default::default(), window, cx)
17122            } else {
17123                self.fold(&Default::default(), window, cx)
17124            }
17125        } else {
17126            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17127            let buffer_ids: HashSet<_> = self
17128                .selections
17129                .disjoint_anchor_ranges()
17130                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17131                .collect();
17132
17133            let should_unfold = buffer_ids
17134                .iter()
17135                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17136
17137            for buffer_id in buffer_ids {
17138                if should_unfold {
17139                    self.unfold_buffer(buffer_id, cx);
17140                } else {
17141                    self.fold_buffer(buffer_id, cx);
17142                }
17143            }
17144        }
17145    }
17146
17147    pub fn toggle_fold_recursive(
17148        &mut self,
17149        _: &actions::ToggleFoldRecursive,
17150        window: &mut Window,
17151        cx: &mut Context<Self>,
17152    ) {
17153        let selection = self.selections.newest::<Point>(cx);
17154
17155        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17156        let range = if selection.is_empty() {
17157            let point = selection.head().to_display_point(&display_map);
17158            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17159            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17160                .to_point(&display_map);
17161            start..end
17162        } else {
17163            selection.range()
17164        };
17165        if display_map.folds_in_range(range).next().is_some() {
17166            self.unfold_recursive(&Default::default(), window, cx)
17167        } else {
17168            self.fold_recursive(&Default::default(), window, cx)
17169        }
17170    }
17171
17172    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17173        if self.is_singleton(cx) {
17174            let mut to_fold = Vec::new();
17175            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17176            let selections = self.selections.all_adjusted(cx);
17177
17178            for selection in selections {
17179                let range = selection.range().sorted();
17180                let buffer_start_row = range.start.row;
17181
17182                if range.start.row != range.end.row {
17183                    let mut found = false;
17184                    let mut row = range.start.row;
17185                    while row <= range.end.row {
17186                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17187                        {
17188                            found = true;
17189                            row = crease.range().end.row + 1;
17190                            to_fold.push(crease);
17191                        } else {
17192                            row += 1
17193                        }
17194                    }
17195                    if found {
17196                        continue;
17197                    }
17198                }
17199
17200                for row in (0..=range.start.row).rev() {
17201                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17202                        if crease.range().end.row >= buffer_start_row {
17203                            to_fold.push(crease);
17204                            if row <= range.start.row {
17205                                break;
17206                            }
17207                        }
17208                    }
17209                }
17210            }
17211
17212            self.fold_creases(to_fold, true, window, cx);
17213        } else {
17214            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17215            let buffer_ids = self
17216                .selections
17217                .disjoint_anchor_ranges()
17218                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17219                .collect::<HashSet<_>>();
17220            for buffer_id in buffer_ids {
17221                self.fold_buffer(buffer_id, cx);
17222            }
17223        }
17224    }
17225
17226    pub fn toggle_fold_all(
17227        &mut self,
17228        _: &actions::ToggleFoldAll,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) {
17232        if self.buffer.read(cx).is_singleton() {
17233            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17234            let has_folds = display_map
17235                .folds_in_range(0..display_map.buffer_snapshot.len())
17236                .next()
17237                .is_some();
17238
17239            if has_folds {
17240                self.unfold_all(&actions::UnfoldAll, window, cx);
17241            } else {
17242                self.fold_all(&actions::FoldAll, window, cx);
17243            }
17244        } else {
17245            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17246            let should_unfold = buffer_ids
17247                .iter()
17248                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17249
17250            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17251                editor
17252                    .update_in(cx, |editor, _, cx| {
17253                        for buffer_id in buffer_ids {
17254                            if should_unfold {
17255                                editor.unfold_buffer(buffer_id, cx);
17256                            } else {
17257                                editor.fold_buffer(buffer_id, cx);
17258                            }
17259                        }
17260                    })
17261                    .ok();
17262            });
17263        }
17264    }
17265
17266    fn fold_at_level(
17267        &mut self,
17268        fold_at: &FoldAtLevel,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) {
17272        if !self.buffer.read(cx).is_singleton() {
17273            return;
17274        }
17275
17276        let fold_at_level = fold_at.0;
17277        let snapshot = self.buffer.read(cx).snapshot(cx);
17278        let mut to_fold = Vec::new();
17279        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17280
17281        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17282            while start_row < end_row {
17283                match self
17284                    .snapshot(window, cx)
17285                    .crease_for_buffer_row(MultiBufferRow(start_row))
17286                {
17287                    Some(crease) => {
17288                        let nested_start_row = crease.range().start.row + 1;
17289                        let nested_end_row = crease.range().end.row;
17290
17291                        if current_level < fold_at_level {
17292                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17293                        } else if current_level == fold_at_level {
17294                            to_fold.push(crease);
17295                        }
17296
17297                        start_row = nested_end_row + 1;
17298                    }
17299                    None => start_row += 1,
17300                }
17301            }
17302        }
17303
17304        self.fold_creases(to_fold, true, window, cx);
17305    }
17306
17307    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17308        if self.buffer.read(cx).is_singleton() {
17309            let mut fold_ranges = Vec::new();
17310            let snapshot = self.buffer.read(cx).snapshot(cx);
17311
17312            for row in 0..snapshot.max_row().0 {
17313                if let Some(foldable_range) = self
17314                    .snapshot(window, cx)
17315                    .crease_for_buffer_row(MultiBufferRow(row))
17316                {
17317                    fold_ranges.push(foldable_range);
17318                }
17319            }
17320
17321            self.fold_creases(fold_ranges, true, window, cx);
17322        } else {
17323            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17324                editor
17325                    .update_in(cx, |editor, _, cx| {
17326                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17327                            editor.fold_buffer(buffer_id, cx);
17328                        }
17329                    })
17330                    .ok();
17331            });
17332        }
17333    }
17334
17335    pub fn fold_function_bodies(
17336        &mut self,
17337        _: &actions::FoldFunctionBodies,
17338        window: &mut Window,
17339        cx: &mut Context<Self>,
17340    ) {
17341        let snapshot = self.buffer.read(cx).snapshot(cx);
17342
17343        let ranges = snapshot
17344            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17345            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17346            .collect::<Vec<_>>();
17347
17348        let creases = ranges
17349            .into_iter()
17350            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17351            .collect();
17352
17353        self.fold_creases(creases, true, window, cx);
17354    }
17355
17356    pub fn fold_recursive(
17357        &mut self,
17358        _: &actions::FoldRecursive,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) {
17362        let mut to_fold = Vec::new();
17363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17364        let selections = self.selections.all_adjusted(cx);
17365
17366        for selection in selections {
17367            let range = selection.range().sorted();
17368            let buffer_start_row = range.start.row;
17369
17370            if range.start.row != range.end.row {
17371                let mut found = false;
17372                for row in range.start.row..=range.end.row {
17373                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17374                        found = true;
17375                        to_fold.push(crease);
17376                    }
17377                }
17378                if found {
17379                    continue;
17380                }
17381            }
17382
17383            for row in (0..=range.start.row).rev() {
17384                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17385                    if crease.range().end.row >= buffer_start_row {
17386                        to_fold.push(crease);
17387                    } else {
17388                        break;
17389                    }
17390                }
17391            }
17392        }
17393
17394        self.fold_creases(to_fold, true, window, cx);
17395    }
17396
17397    pub fn fold_at(
17398        &mut self,
17399        buffer_row: MultiBufferRow,
17400        window: &mut Window,
17401        cx: &mut Context<Self>,
17402    ) {
17403        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17404
17405        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17406            let autoscroll = self
17407                .selections
17408                .all::<Point>(cx)
17409                .iter()
17410                .any(|selection| crease.range().overlaps(&selection.range()));
17411
17412            self.fold_creases(vec![crease], autoscroll, window, cx);
17413        }
17414    }
17415
17416    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17417        if self.is_singleton(cx) {
17418            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17419            let buffer = &display_map.buffer_snapshot;
17420            let selections = self.selections.all::<Point>(cx);
17421            let ranges = selections
17422                .iter()
17423                .map(|s| {
17424                    let range = s.display_range(&display_map).sorted();
17425                    let mut start = range.start.to_point(&display_map);
17426                    let mut end = range.end.to_point(&display_map);
17427                    start.column = 0;
17428                    end.column = buffer.line_len(MultiBufferRow(end.row));
17429                    start..end
17430                })
17431                .collect::<Vec<_>>();
17432
17433            self.unfold_ranges(&ranges, true, true, cx);
17434        } else {
17435            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17436            let buffer_ids = self
17437                .selections
17438                .disjoint_anchor_ranges()
17439                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17440                .collect::<HashSet<_>>();
17441            for buffer_id in buffer_ids {
17442                self.unfold_buffer(buffer_id, cx);
17443            }
17444        }
17445    }
17446
17447    pub fn unfold_recursive(
17448        &mut self,
17449        _: &UnfoldRecursive,
17450        _window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) {
17453        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17454        let selections = self.selections.all::<Point>(cx);
17455        let ranges = selections
17456            .iter()
17457            .map(|s| {
17458                let mut range = s.display_range(&display_map).sorted();
17459                *range.start.column_mut() = 0;
17460                *range.end.column_mut() = display_map.line_len(range.end.row());
17461                let start = range.start.to_point(&display_map);
17462                let end = range.end.to_point(&display_map);
17463                start..end
17464            })
17465            .collect::<Vec<_>>();
17466
17467        self.unfold_ranges(&ranges, true, true, cx);
17468    }
17469
17470    pub fn unfold_at(
17471        &mut self,
17472        buffer_row: MultiBufferRow,
17473        _window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) {
17476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17477
17478        let intersection_range = Point::new(buffer_row.0, 0)
17479            ..Point::new(
17480                buffer_row.0,
17481                display_map.buffer_snapshot.line_len(buffer_row),
17482            );
17483
17484        let autoscroll = self
17485            .selections
17486            .all::<Point>(cx)
17487            .iter()
17488            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17489
17490        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17491    }
17492
17493    pub fn unfold_all(
17494        &mut self,
17495        _: &actions::UnfoldAll,
17496        _window: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) {
17499        if self.buffer.read(cx).is_singleton() {
17500            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17501            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17502        } else {
17503            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17504                editor
17505                    .update(cx, |editor, cx| {
17506                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17507                            editor.unfold_buffer(buffer_id, cx);
17508                        }
17509                    })
17510                    .ok();
17511            });
17512        }
17513    }
17514
17515    pub fn fold_selected_ranges(
17516        &mut self,
17517        _: &FoldSelectedRanges,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) {
17521        let selections = self.selections.all_adjusted(cx);
17522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17523        let ranges = selections
17524            .into_iter()
17525            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17526            .collect::<Vec<_>>();
17527        self.fold_creases(ranges, true, window, cx);
17528    }
17529
17530    pub fn fold_ranges<T: ToOffset + Clone>(
17531        &mut self,
17532        ranges: Vec<Range<T>>,
17533        auto_scroll: bool,
17534        window: &mut Window,
17535        cx: &mut Context<Self>,
17536    ) {
17537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17538        let ranges = ranges
17539            .into_iter()
17540            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17541            .collect::<Vec<_>>();
17542        self.fold_creases(ranges, auto_scroll, window, cx);
17543    }
17544
17545    pub fn fold_creases<T: ToOffset + Clone>(
17546        &mut self,
17547        creases: Vec<Crease<T>>,
17548        auto_scroll: bool,
17549        _window: &mut Window,
17550        cx: &mut Context<Self>,
17551    ) {
17552        if creases.is_empty() {
17553            return;
17554        }
17555
17556        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17557
17558        if auto_scroll {
17559            self.request_autoscroll(Autoscroll::fit(), cx);
17560        }
17561
17562        cx.notify();
17563
17564        self.scrollbar_marker_state.dirty = true;
17565        self.folds_did_change(cx);
17566    }
17567
17568    /// Removes any folds whose ranges intersect any of the given ranges.
17569    pub fn unfold_ranges<T: ToOffset + Clone>(
17570        &mut self,
17571        ranges: &[Range<T>],
17572        inclusive: bool,
17573        auto_scroll: bool,
17574        cx: &mut Context<Self>,
17575    ) {
17576        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17577            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17578        });
17579        self.folds_did_change(cx);
17580    }
17581
17582    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17583        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17584            return;
17585        }
17586        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17587        self.display_map.update(cx, |display_map, cx| {
17588            display_map.fold_buffers([buffer_id], cx)
17589        });
17590        cx.emit(EditorEvent::BufferFoldToggled {
17591            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17592            folded: true,
17593        });
17594        cx.notify();
17595    }
17596
17597    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17598        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17599            return;
17600        }
17601        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17602        self.display_map.update(cx, |display_map, cx| {
17603            display_map.unfold_buffers([buffer_id], cx);
17604        });
17605        cx.emit(EditorEvent::BufferFoldToggled {
17606            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17607            folded: false,
17608        });
17609        cx.notify();
17610    }
17611
17612    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17613        self.display_map.read(cx).is_buffer_folded(buffer)
17614    }
17615
17616    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17617        self.display_map.read(cx).folded_buffers()
17618    }
17619
17620    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17621        self.display_map.update(cx, |display_map, cx| {
17622            display_map.disable_header_for_buffer(buffer_id, cx);
17623        });
17624        cx.notify();
17625    }
17626
17627    /// Removes any folds with the given ranges.
17628    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17629        &mut self,
17630        ranges: &[Range<T>],
17631        type_id: TypeId,
17632        auto_scroll: bool,
17633        cx: &mut Context<Self>,
17634    ) {
17635        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17636            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17637        });
17638        self.folds_did_change(cx);
17639    }
17640
17641    fn remove_folds_with<T: ToOffset + Clone>(
17642        &mut self,
17643        ranges: &[Range<T>],
17644        auto_scroll: bool,
17645        cx: &mut Context<Self>,
17646        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17647    ) {
17648        if ranges.is_empty() {
17649            return;
17650        }
17651
17652        let mut buffers_affected = HashSet::default();
17653        let multi_buffer = self.buffer().read(cx);
17654        for range in ranges {
17655            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17656                buffers_affected.insert(buffer.read(cx).remote_id());
17657            };
17658        }
17659
17660        self.display_map.update(cx, update);
17661
17662        if auto_scroll {
17663            self.request_autoscroll(Autoscroll::fit(), cx);
17664        }
17665
17666        cx.notify();
17667        self.scrollbar_marker_state.dirty = true;
17668        self.active_indent_guides_state.dirty = true;
17669    }
17670
17671    pub fn update_renderer_widths(
17672        &mut self,
17673        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17674        cx: &mut Context<Self>,
17675    ) -> bool {
17676        self.display_map
17677            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17678    }
17679
17680    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17681        self.display_map.read(cx).fold_placeholder.clone()
17682    }
17683
17684    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17685        self.buffer.update(cx, |buffer, cx| {
17686            buffer.set_all_diff_hunks_expanded(cx);
17687        });
17688    }
17689
17690    pub fn expand_all_diff_hunks(
17691        &mut self,
17692        _: &ExpandAllDiffHunks,
17693        _window: &mut Window,
17694        cx: &mut Context<Self>,
17695    ) {
17696        self.buffer.update(cx, |buffer, cx| {
17697            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17698        });
17699    }
17700
17701    pub fn toggle_selected_diff_hunks(
17702        &mut self,
17703        _: &ToggleSelectedDiffHunks,
17704        _window: &mut Window,
17705        cx: &mut Context<Self>,
17706    ) {
17707        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17708        self.toggle_diff_hunks_in_ranges(ranges, cx);
17709    }
17710
17711    pub fn diff_hunks_in_ranges<'a>(
17712        &'a self,
17713        ranges: &'a [Range<Anchor>],
17714        buffer: &'a MultiBufferSnapshot,
17715    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17716        ranges.iter().flat_map(move |range| {
17717            let end_excerpt_id = range.end.excerpt_id;
17718            let range = range.to_point(buffer);
17719            let mut peek_end = range.end;
17720            if range.end.row < buffer.max_row().0 {
17721                peek_end = Point::new(range.end.row + 1, 0);
17722            }
17723            buffer
17724                .diff_hunks_in_range(range.start..peek_end)
17725                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17726        })
17727    }
17728
17729    pub fn has_stageable_diff_hunks_in_ranges(
17730        &self,
17731        ranges: &[Range<Anchor>],
17732        snapshot: &MultiBufferSnapshot,
17733    ) -> bool {
17734        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17735        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17736    }
17737
17738    pub fn toggle_staged_selected_diff_hunks(
17739        &mut self,
17740        _: &::git::ToggleStaged,
17741        _: &mut Window,
17742        cx: &mut Context<Self>,
17743    ) {
17744        let snapshot = self.buffer.read(cx).snapshot(cx);
17745        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17746        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17747        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17748    }
17749
17750    pub fn set_render_diff_hunk_controls(
17751        &mut self,
17752        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17753        cx: &mut Context<Self>,
17754    ) {
17755        self.render_diff_hunk_controls = render_diff_hunk_controls;
17756        cx.notify();
17757    }
17758
17759    pub fn stage_and_next(
17760        &mut self,
17761        _: &::git::StageAndNext,
17762        window: &mut Window,
17763        cx: &mut Context<Self>,
17764    ) {
17765        self.do_stage_or_unstage_and_next(true, window, cx);
17766    }
17767
17768    pub fn unstage_and_next(
17769        &mut self,
17770        _: &::git::UnstageAndNext,
17771        window: &mut Window,
17772        cx: &mut Context<Self>,
17773    ) {
17774        self.do_stage_or_unstage_and_next(false, window, cx);
17775    }
17776
17777    pub fn stage_or_unstage_diff_hunks(
17778        &mut self,
17779        stage: bool,
17780        ranges: Vec<Range<Anchor>>,
17781        cx: &mut Context<Self>,
17782    ) {
17783        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17784        cx.spawn(async move |this, cx| {
17785            task.await?;
17786            this.update(cx, |this, cx| {
17787                let snapshot = this.buffer.read(cx).snapshot(cx);
17788                let chunk_by = this
17789                    .diff_hunks_in_ranges(&ranges, &snapshot)
17790                    .chunk_by(|hunk| hunk.buffer_id);
17791                for (buffer_id, hunks) in &chunk_by {
17792                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17793                }
17794            })
17795        })
17796        .detach_and_log_err(cx);
17797    }
17798
17799    fn save_buffers_for_ranges_if_needed(
17800        &mut self,
17801        ranges: &[Range<Anchor>],
17802        cx: &mut Context<Editor>,
17803    ) -> Task<Result<()>> {
17804        let multibuffer = self.buffer.read(cx);
17805        let snapshot = multibuffer.read(cx);
17806        let buffer_ids: HashSet<_> = ranges
17807            .iter()
17808            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17809            .collect();
17810        drop(snapshot);
17811
17812        let mut buffers = HashSet::default();
17813        for buffer_id in buffer_ids {
17814            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17815                let buffer = buffer_entity.read(cx);
17816                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17817                {
17818                    buffers.insert(buffer_entity);
17819                }
17820            }
17821        }
17822
17823        if let Some(project) = &self.project {
17824            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17825        } else {
17826            Task::ready(Ok(()))
17827        }
17828    }
17829
17830    fn do_stage_or_unstage_and_next(
17831        &mut self,
17832        stage: bool,
17833        window: &mut Window,
17834        cx: &mut Context<Self>,
17835    ) {
17836        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17837
17838        if ranges.iter().any(|range| range.start != range.end) {
17839            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17840            return;
17841        }
17842
17843        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17844        let snapshot = self.snapshot(window, cx);
17845        let position = self.selections.newest::<Point>(cx).head();
17846        let mut row = snapshot
17847            .buffer_snapshot
17848            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17849            .find(|hunk| hunk.row_range.start.0 > position.row)
17850            .map(|hunk| hunk.row_range.start);
17851
17852        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17853        // Outside of the project diff editor, wrap around to the beginning.
17854        if !all_diff_hunks_expanded {
17855            row = row.or_else(|| {
17856                snapshot
17857                    .buffer_snapshot
17858                    .diff_hunks_in_range(Point::zero()..position)
17859                    .find(|hunk| hunk.row_range.end.0 < position.row)
17860                    .map(|hunk| hunk.row_range.start)
17861            });
17862        }
17863
17864        if let Some(row) = row {
17865            let destination = Point::new(row.0, 0);
17866            let autoscroll = Autoscroll::center();
17867
17868            self.unfold_ranges(&[destination..destination], false, false, cx);
17869            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17870                s.select_ranges([destination..destination]);
17871            });
17872        }
17873    }
17874
17875    fn do_stage_or_unstage(
17876        &self,
17877        stage: bool,
17878        buffer_id: BufferId,
17879        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17880        cx: &mut App,
17881    ) -> Option<()> {
17882        let project = self.project.as_ref()?;
17883        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17884        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17885        let buffer_snapshot = buffer.read(cx).snapshot();
17886        let file_exists = buffer_snapshot
17887            .file()
17888            .is_some_and(|file| file.disk_state().exists());
17889        diff.update(cx, |diff, cx| {
17890            diff.stage_or_unstage_hunks(
17891                stage,
17892                &hunks
17893                    .map(|hunk| buffer_diff::DiffHunk {
17894                        buffer_range: hunk.buffer_range,
17895                        diff_base_byte_range: hunk.diff_base_byte_range,
17896                        secondary_status: hunk.secondary_status,
17897                        range: Point::zero()..Point::zero(), // unused
17898                    })
17899                    .collect::<Vec<_>>(),
17900                &buffer_snapshot,
17901                file_exists,
17902                cx,
17903            )
17904        });
17905        None
17906    }
17907
17908    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17909        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17910        self.buffer
17911            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17912    }
17913
17914    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17915        self.buffer.update(cx, |buffer, cx| {
17916            let ranges = vec![Anchor::min()..Anchor::max()];
17917            if !buffer.all_diff_hunks_expanded()
17918                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17919            {
17920                buffer.collapse_diff_hunks(ranges, cx);
17921                true
17922            } else {
17923                false
17924            }
17925        })
17926    }
17927
17928    fn toggle_diff_hunks_in_ranges(
17929        &mut self,
17930        ranges: Vec<Range<Anchor>>,
17931        cx: &mut Context<Editor>,
17932    ) {
17933        self.buffer.update(cx, |buffer, cx| {
17934            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17935            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17936        })
17937    }
17938
17939    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17940        self.buffer.update(cx, |buffer, cx| {
17941            let snapshot = buffer.snapshot(cx);
17942            let excerpt_id = range.end.excerpt_id;
17943            let point_range = range.to_point(&snapshot);
17944            let expand = !buffer.single_hunk_is_expanded(range, cx);
17945            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17946        })
17947    }
17948
17949    pub(crate) fn apply_all_diff_hunks(
17950        &mut self,
17951        _: &ApplyAllDiffHunks,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17956
17957        let buffers = self.buffer.read(cx).all_buffers();
17958        for branch_buffer in buffers {
17959            branch_buffer.update(cx, |branch_buffer, cx| {
17960                branch_buffer.merge_into_base(Vec::new(), cx);
17961            });
17962        }
17963
17964        if let Some(project) = self.project.clone() {
17965            self.save(
17966                SaveOptions {
17967                    format: true,
17968                    autosave: false,
17969                },
17970                project,
17971                window,
17972                cx,
17973            )
17974            .detach_and_log_err(cx);
17975        }
17976    }
17977
17978    pub(crate) fn apply_selected_diff_hunks(
17979        &mut self,
17980        _: &ApplyDiffHunk,
17981        window: &mut Window,
17982        cx: &mut Context<Self>,
17983    ) {
17984        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17985        let snapshot = self.snapshot(window, cx);
17986        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17987        let mut ranges_by_buffer = HashMap::default();
17988        self.transact(window, cx, |editor, _window, cx| {
17989            for hunk in hunks {
17990                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17991                    ranges_by_buffer
17992                        .entry(buffer.clone())
17993                        .or_insert_with(Vec::new)
17994                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17995                }
17996            }
17997
17998            for (buffer, ranges) in ranges_by_buffer {
17999                buffer.update(cx, |buffer, cx| {
18000                    buffer.merge_into_base(ranges, cx);
18001                });
18002            }
18003        });
18004
18005        if let Some(project) = self.project.clone() {
18006            self.save(
18007                SaveOptions {
18008                    format: true,
18009                    autosave: false,
18010                },
18011                project,
18012                window,
18013                cx,
18014            )
18015            .detach_and_log_err(cx);
18016        }
18017    }
18018
18019    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18020        if hovered != self.gutter_hovered {
18021            self.gutter_hovered = hovered;
18022            cx.notify();
18023        }
18024    }
18025
18026    pub fn insert_blocks(
18027        &mut self,
18028        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18029        autoscroll: Option<Autoscroll>,
18030        cx: &mut Context<Self>,
18031    ) -> Vec<CustomBlockId> {
18032        let blocks = self
18033            .display_map
18034            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18035        if let Some(autoscroll) = autoscroll {
18036            self.request_autoscroll(autoscroll, cx);
18037        }
18038        cx.notify();
18039        blocks
18040    }
18041
18042    pub fn resize_blocks(
18043        &mut self,
18044        heights: HashMap<CustomBlockId, u32>,
18045        autoscroll: Option<Autoscroll>,
18046        cx: &mut Context<Self>,
18047    ) {
18048        self.display_map
18049            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18050        if let Some(autoscroll) = autoscroll {
18051            self.request_autoscroll(autoscroll, cx);
18052        }
18053        cx.notify();
18054    }
18055
18056    pub fn replace_blocks(
18057        &mut self,
18058        renderers: HashMap<CustomBlockId, RenderBlock>,
18059        autoscroll: Option<Autoscroll>,
18060        cx: &mut Context<Self>,
18061    ) {
18062        self.display_map
18063            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18064        if let Some(autoscroll) = autoscroll {
18065            self.request_autoscroll(autoscroll, cx);
18066        }
18067        cx.notify();
18068    }
18069
18070    pub fn remove_blocks(
18071        &mut self,
18072        block_ids: HashSet<CustomBlockId>,
18073        autoscroll: Option<Autoscroll>,
18074        cx: &mut Context<Self>,
18075    ) {
18076        self.display_map.update(cx, |display_map, cx| {
18077            display_map.remove_blocks(block_ids, cx)
18078        });
18079        if let Some(autoscroll) = autoscroll {
18080            self.request_autoscroll(autoscroll, cx);
18081        }
18082        cx.notify();
18083    }
18084
18085    pub fn row_for_block(
18086        &self,
18087        block_id: CustomBlockId,
18088        cx: &mut Context<Self>,
18089    ) -> Option<DisplayRow> {
18090        self.display_map
18091            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18092    }
18093
18094    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18095        self.focused_block = Some(focused_block);
18096    }
18097
18098    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18099        self.focused_block.take()
18100    }
18101
18102    pub fn insert_creases(
18103        &mut self,
18104        creases: impl IntoIterator<Item = Crease<Anchor>>,
18105        cx: &mut Context<Self>,
18106    ) -> Vec<CreaseId> {
18107        self.display_map
18108            .update(cx, |map, cx| map.insert_creases(creases, cx))
18109    }
18110
18111    pub fn remove_creases(
18112        &mut self,
18113        ids: impl IntoIterator<Item = CreaseId>,
18114        cx: &mut Context<Self>,
18115    ) -> Vec<(CreaseId, Range<Anchor>)> {
18116        self.display_map
18117            .update(cx, |map, cx| map.remove_creases(ids, cx))
18118    }
18119
18120    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18121        self.display_map
18122            .update(cx, |map, cx| map.snapshot(cx))
18123            .longest_row()
18124    }
18125
18126    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18127        self.display_map
18128            .update(cx, |map, cx| map.snapshot(cx))
18129            .max_point()
18130    }
18131
18132    pub fn text(&self, cx: &App) -> String {
18133        self.buffer.read(cx).read(cx).text()
18134    }
18135
18136    pub fn is_empty(&self, cx: &App) -> bool {
18137        self.buffer.read(cx).read(cx).is_empty()
18138    }
18139
18140    pub fn text_option(&self, cx: &App) -> Option<String> {
18141        let text = self.text(cx);
18142        let text = text.trim();
18143
18144        if text.is_empty() {
18145            return None;
18146        }
18147
18148        Some(text.to_string())
18149    }
18150
18151    pub fn set_text(
18152        &mut self,
18153        text: impl Into<Arc<str>>,
18154        window: &mut Window,
18155        cx: &mut Context<Self>,
18156    ) {
18157        self.transact(window, cx, |this, _, cx| {
18158            this.buffer
18159                .read(cx)
18160                .as_singleton()
18161                .expect("you can only call set_text on editors for singleton buffers")
18162                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18163        });
18164    }
18165
18166    pub fn display_text(&self, cx: &mut App) -> String {
18167        self.display_map
18168            .update(cx, |map, cx| map.snapshot(cx))
18169            .text()
18170    }
18171
18172    fn create_minimap(
18173        &self,
18174        minimap_settings: MinimapSettings,
18175        window: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) -> Option<Entity<Self>> {
18178        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18179            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18180    }
18181
18182    fn initialize_new_minimap(
18183        &self,
18184        minimap_settings: MinimapSettings,
18185        window: &mut Window,
18186        cx: &mut Context<Self>,
18187    ) -> Entity<Self> {
18188        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18189
18190        let mut minimap = Editor::new_internal(
18191            EditorMode::Minimap {
18192                parent: cx.weak_entity(),
18193            },
18194            self.buffer.clone(),
18195            None,
18196            Some(self.display_map.clone()),
18197            window,
18198            cx,
18199        );
18200        minimap.scroll_manager.clone_state(&self.scroll_manager);
18201        minimap.set_text_style_refinement(TextStyleRefinement {
18202            font_size: Some(MINIMAP_FONT_SIZE),
18203            font_weight: Some(MINIMAP_FONT_WEIGHT),
18204            ..Default::default()
18205        });
18206        minimap.update_minimap_configuration(minimap_settings, cx);
18207        cx.new(|_| minimap)
18208    }
18209
18210    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18211        let current_line_highlight = minimap_settings
18212            .current_line_highlight
18213            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18214        self.set_current_line_highlight(Some(current_line_highlight));
18215    }
18216
18217    pub fn minimap(&self) -> Option<&Entity<Self>> {
18218        self.minimap
18219            .as_ref()
18220            .filter(|_| self.minimap_visibility.visible())
18221    }
18222
18223    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18224        let mut wrap_guides = smallvec![];
18225
18226        if self.show_wrap_guides == Some(false) {
18227            return wrap_guides;
18228        }
18229
18230        let settings = self.buffer.read(cx).language_settings(cx);
18231        if settings.show_wrap_guides {
18232            match self.soft_wrap_mode(cx) {
18233                SoftWrap::Column(soft_wrap) => {
18234                    wrap_guides.push((soft_wrap as usize, true));
18235                }
18236                SoftWrap::Bounded(soft_wrap) => {
18237                    wrap_guides.push((soft_wrap as usize, true));
18238                }
18239                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18240            }
18241            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18242        }
18243
18244        wrap_guides
18245    }
18246
18247    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18248        let settings = self.buffer.read(cx).language_settings(cx);
18249        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18250        match mode {
18251            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18252                SoftWrap::None
18253            }
18254            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18255            language_settings::SoftWrap::PreferredLineLength => {
18256                SoftWrap::Column(settings.preferred_line_length)
18257            }
18258            language_settings::SoftWrap::Bounded => {
18259                SoftWrap::Bounded(settings.preferred_line_length)
18260            }
18261        }
18262    }
18263
18264    pub fn set_soft_wrap_mode(
18265        &mut self,
18266        mode: language_settings::SoftWrap,
18267
18268        cx: &mut Context<Self>,
18269    ) {
18270        self.soft_wrap_mode_override = Some(mode);
18271        cx.notify();
18272    }
18273
18274    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18275        self.hard_wrap = hard_wrap;
18276        cx.notify();
18277    }
18278
18279    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18280        self.text_style_refinement = Some(style);
18281    }
18282
18283    /// called by the Element so we know what style we were most recently rendered with.
18284    pub(crate) fn set_style(
18285        &mut self,
18286        style: EditorStyle,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        // We intentionally do not inform the display map about the minimap style
18291        // so that wrapping is not recalculated and stays consistent for the editor
18292        // and its linked minimap.
18293        if !self.mode.is_minimap() {
18294            let rem_size = window.rem_size();
18295            self.display_map.update(cx, |map, cx| {
18296                map.set_font(
18297                    style.text.font(),
18298                    style.text.font_size.to_pixels(rem_size),
18299                    cx,
18300                )
18301            });
18302        }
18303        self.style = Some(style);
18304    }
18305
18306    pub fn style(&self) -> Option<&EditorStyle> {
18307        self.style.as_ref()
18308    }
18309
18310    // Called by the element. This method is not designed to be called outside of the editor
18311    // element's layout code because it does not notify when rewrapping is computed synchronously.
18312    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18313        self.display_map
18314            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18315    }
18316
18317    pub fn set_soft_wrap(&mut self) {
18318        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18319    }
18320
18321    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18322        if self.soft_wrap_mode_override.is_some() {
18323            self.soft_wrap_mode_override.take();
18324        } else {
18325            let soft_wrap = match self.soft_wrap_mode(cx) {
18326                SoftWrap::GitDiff => return,
18327                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18328                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18329                    language_settings::SoftWrap::None
18330                }
18331            };
18332            self.soft_wrap_mode_override = Some(soft_wrap);
18333        }
18334        cx.notify();
18335    }
18336
18337    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18338        let Some(workspace) = self.workspace() else {
18339            return;
18340        };
18341        let fs = workspace.read(cx).app_state().fs.clone();
18342        let current_show = TabBarSettings::get_global(cx).show;
18343        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18344            setting.show = Some(!current_show);
18345        });
18346    }
18347
18348    pub fn toggle_indent_guides(
18349        &mut self,
18350        _: &ToggleIndentGuides,
18351        _: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18355            self.buffer
18356                .read(cx)
18357                .language_settings(cx)
18358                .indent_guides
18359                .enabled
18360        });
18361        self.show_indent_guides = Some(!currently_enabled);
18362        cx.notify();
18363    }
18364
18365    fn should_show_indent_guides(&self) -> Option<bool> {
18366        self.show_indent_guides
18367    }
18368
18369    pub fn toggle_line_numbers(
18370        &mut self,
18371        _: &ToggleLineNumbers,
18372        _: &mut Window,
18373        cx: &mut Context<Self>,
18374    ) {
18375        let mut editor_settings = EditorSettings::get_global(cx).clone();
18376        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18377        EditorSettings::override_global(editor_settings, cx);
18378    }
18379
18380    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18381        if let Some(show_line_numbers) = self.show_line_numbers {
18382            return show_line_numbers;
18383        }
18384        EditorSettings::get_global(cx).gutter.line_numbers
18385    }
18386
18387    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18388        self.use_relative_line_numbers
18389            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18390    }
18391
18392    pub fn toggle_relative_line_numbers(
18393        &mut self,
18394        _: &ToggleRelativeLineNumbers,
18395        _: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        let is_relative = self.should_use_relative_line_numbers(cx);
18399        self.set_relative_line_number(Some(!is_relative), cx)
18400    }
18401
18402    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18403        self.use_relative_line_numbers = is_relative;
18404        cx.notify();
18405    }
18406
18407    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18408        self.show_gutter = show_gutter;
18409        cx.notify();
18410    }
18411
18412    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18413        self.show_scrollbars = ScrollbarAxes {
18414            horizontal: show,
18415            vertical: show,
18416        };
18417        cx.notify();
18418    }
18419
18420    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18421        self.show_scrollbars.vertical = show;
18422        cx.notify();
18423    }
18424
18425    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18426        self.show_scrollbars.horizontal = show;
18427        cx.notify();
18428    }
18429
18430    pub fn set_minimap_visibility(
18431        &mut self,
18432        minimap_visibility: MinimapVisibility,
18433        window: &mut Window,
18434        cx: &mut Context<Self>,
18435    ) {
18436        if self.minimap_visibility != minimap_visibility {
18437            if minimap_visibility.visible() && self.minimap.is_none() {
18438                let minimap_settings = EditorSettings::get_global(cx).minimap;
18439                self.minimap =
18440                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18441            }
18442            self.minimap_visibility = minimap_visibility;
18443            cx.notify();
18444        }
18445    }
18446
18447    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18448        self.set_show_scrollbars(false, cx);
18449        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18450    }
18451
18452    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18453        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18454    }
18455
18456    /// Normally the text in full mode and auto height editors is padded on the
18457    /// left side by roughly half a character width for improved hit testing.
18458    ///
18459    /// Use this method to disable this for cases where this is not wanted (e.g.
18460    /// if you want to align the editor text with some other text above or below)
18461    /// or if you want to add this padding to single-line editors.
18462    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18463        self.offset_content = offset_content;
18464        cx.notify();
18465    }
18466
18467    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18468        self.show_line_numbers = Some(show_line_numbers);
18469        cx.notify();
18470    }
18471
18472    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18473        self.disable_expand_excerpt_buttons = true;
18474        cx.notify();
18475    }
18476
18477    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18478        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18479        cx.notify();
18480    }
18481
18482    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18483        self.show_code_actions = Some(show_code_actions);
18484        cx.notify();
18485    }
18486
18487    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18488        self.show_runnables = Some(show_runnables);
18489        cx.notify();
18490    }
18491
18492    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18493        self.show_breakpoints = Some(show_breakpoints);
18494        cx.notify();
18495    }
18496
18497    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18498        if self.display_map.read(cx).masked != masked {
18499            self.display_map.update(cx, |map, _| map.masked = masked);
18500        }
18501        cx.notify()
18502    }
18503
18504    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18505        self.show_wrap_guides = Some(show_wrap_guides);
18506        cx.notify();
18507    }
18508
18509    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18510        self.show_indent_guides = Some(show_indent_guides);
18511        cx.notify();
18512    }
18513
18514    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18515        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18516            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18517                if let Some(dir) = file.abs_path(cx).parent() {
18518                    return Some(dir.to_owned());
18519                }
18520            }
18521
18522            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18523                return Some(project_path.path.to_path_buf());
18524            }
18525        }
18526
18527        None
18528    }
18529
18530    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18531        self.active_excerpt(cx)?
18532            .1
18533            .read(cx)
18534            .file()
18535            .and_then(|f| f.as_local())
18536    }
18537
18538    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18539        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18540            let buffer = buffer.read(cx);
18541            if let Some(project_path) = buffer.project_path(cx) {
18542                let project = self.project.as_ref()?.read(cx);
18543                project.absolute_path(&project_path, cx)
18544            } else {
18545                buffer
18546                    .file()
18547                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18548            }
18549        })
18550    }
18551
18552    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18553        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18554            let project_path = buffer.read(cx).project_path(cx)?;
18555            let project = self.project.as_ref()?.read(cx);
18556            let entry = project.entry_for_path(&project_path, cx)?;
18557            let path = entry.path.to_path_buf();
18558            Some(path)
18559        })
18560    }
18561
18562    pub fn reveal_in_finder(
18563        &mut self,
18564        _: &RevealInFileManager,
18565        _window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        if let Some(target) = self.target_file(cx) {
18569            cx.reveal_path(&target.abs_path(cx));
18570        }
18571    }
18572
18573    pub fn copy_path(
18574        &mut self,
18575        _: &zed_actions::workspace::CopyPath,
18576        _window: &mut Window,
18577        cx: &mut Context<Self>,
18578    ) {
18579        if let Some(path) = self.target_file_abs_path(cx) {
18580            if let Some(path) = path.to_str() {
18581                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18582            }
18583        }
18584    }
18585
18586    pub fn copy_relative_path(
18587        &mut self,
18588        _: &zed_actions::workspace::CopyRelativePath,
18589        _window: &mut Window,
18590        cx: &mut Context<Self>,
18591    ) {
18592        if let Some(path) = self.target_file_path(cx) {
18593            if let Some(path) = path.to_str() {
18594                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18595            }
18596        }
18597    }
18598
18599    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18600        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18601            buffer.read(cx).project_path(cx)
18602        } else {
18603            None
18604        }
18605    }
18606
18607    // Returns true if the editor handled a go-to-line request
18608    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18609        maybe!({
18610            let breakpoint_store = self.breakpoint_store.as_ref()?;
18611
18612            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18613            else {
18614                self.clear_row_highlights::<ActiveDebugLine>();
18615                return None;
18616            };
18617
18618            let position = active_stack_frame.position;
18619            let buffer_id = position.buffer_id?;
18620            let snapshot = self
18621                .project
18622                .as_ref()?
18623                .read(cx)
18624                .buffer_for_id(buffer_id, cx)?
18625                .read(cx)
18626                .snapshot();
18627
18628            let mut handled = false;
18629            for (id, ExcerptRange { context, .. }) in
18630                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18631            {
18632                if context.start.cmp(&position, &snapshot).is_ge()
18633                    || context.end.cmp(&position, &snapshot).is_lt()
18634                {
18635                    continue;
18636                }
18637                let snapshot = self.buffer.read(cx).snapshot(cx);
18638                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18639
18640                handled = true;
18641                self.clear_row_highlights::<ActiveDebugLine>();
18642
18643                self.go_to_line::<ActiveDebugLine>(
18644                    multibuffer_anchor,
18645                    Some(cx.theme().colors().editor_debugger_active_line_background),
18646                    window,
18647                    cx,
18648                );
18649
18650                cx.notify();
18651            }
18652
18653            handled.then_some(())
18654        })
18655        .is_some()
18656    }
18657
18658    pub fn copy_file_name_without_extension(
18659        &mut self,
18660        _: &CopyFileNameWithoutExtension,
18661        _: &mut Window,
18662        cx: &mut Context<Self>,
18663    ) {
18664        if let Some(file) = self.target_file(cx) {
18665            if let Some(file_stem) = file.path().file_stem() {
18666                if let Some(name) = file_stem.to_str() {
18667                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18668                }
18669            }
18670        }
18671    }
18672
18673    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18674        if let Some(file) = self.target_file(cx) {
18675            if let Some(file_name) = file.path().file_name() {
18676                if let Some(name) = file_name.to_str() {
18677                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18678                }
18679            }
18680        }
18681    }
18682
18683    pub fn toggle_git_blame(
18684        &mut self,
18685        _: &::git::Blame,
18686        window: &mut Window,
18687        cx: &mut Context<Self>,
18688    ) {
18689        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18690
18691        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18692            self.start_git_blame(true, window, cx);
18693        }
18694
18695        cx.notify();
18696    }
18697
18698    pub fn toggle_git_blame_inline(
18699        &mut self,
18700        _: &ToggleGitBlameInline,
18701        window: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        self.toggle_git_blame_inline_internal(true, window, cx);
18705        cx.notify();
18706    }
18707
18708    pub fn open_git_blame_commit(
18709        &mut self,
18710        _: &OpenGitBlameCommit,
18711        window: &mut Window,
18712        cx: &mut Context<Self>,
18713    ) {
18714        self.open_git_blame_commit_internal(window, cx);
18715    }
18716
18717    fn open_git_blame_commit_internal(
18718        &mut self,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) -> Option<()> {
18722        let blame = self.blame.as_ref()?;
18723        let snapshot = self.snapshot(window, cx);
18724        let cursor = self.selections.newest::<Point>(cx).head();
18725        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18726        let blame_entry = blame
18727            .update(cx, |blame, cx| {
18728                blame
18729                    .blame_for_rows(
18730                        &[RowInfo {
18731                            buffer_id: Some(buffer.remote_id()),
18732                            buffer_row: Some(point.row),
18733                            ..Default::default()
18734                        }],
18735                        cx,
18736                    )
18737                    .next()
18738            })
18739            .flatten()?;
18740        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18741        let repo = blame.read(cx).repository(cx)?;
18742        let workspace = self.workspace()?.downgrade();
18743        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18744        None
18745    }
18746
18747    pub fn git_blame_inline_enabled(&self) -> bool {
18748        self.git_blame_inline_enabled
18749    }
18750
18751    pub fn toggle_selection_menu(
18752        &mut self,
18753        _: &ToggleSelectionMenu,
18754        _: &mut Window,
18755        cx: &mut Context<Self>,
18756    ) {
18757        self.show_selection_menu = self
18758            .show_selection_menu
18759            .map(|show_selections_menu| !show_selections_menu)
18760            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18761
18762        cx.notify();
18763    }
18764
18765    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18766        self.show_selection_menu
18767            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18768    }
18769
18770    fn start_git_blame(
18771        &mut self,
18772        user_triggered: bool,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        if let Some(project) = self.project.as_ref() {
18777            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18778                return;
18779            };
18780
18781            if buffer.read(cx).file().is_none() {
18782                return;
18783            }
18784
18785            let focused = self.focus_handle(cx).contains_focused(window, cx);
18786
18787            let project = project.clone();
18788            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18789            self.blame_subscription =
18790                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18791            self.blame = Some(blame);
18792        }
18793    }
18794
18795    fn toggle_git_blame_inline_internal(
18796        &mut self,
18797        user_triggered: bool,
18798        window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        if self.git_blame_inline_enabled {
18802            self.git_blame_inline_enabled = false;
18803            self.show_git_blame_inline = false;
18804            self.show_git_blame_inline_delay_task.take();
18805        } else {
18806            self.git_blame_inline_enabled = true;
18807            self.start_git_blame_inline(user_triggered, window, cx);
18808        }
18809
18810        cx.notify();
18811    }
18812
18813    fn start_git_blame_inline(
18814        &mut self,
18815        user_triggered: bool,
18816        window: &mut Window,
18817        cx: &mut Context<Self>,
18818    ) {
18819        self.start_git_blame(user_triggered, window, cx);
18820
18821        if ProjectSettings::get_global(cx)
18822            .git
18823            .inline_blame_delay()
18824            .is_some()
18825        {
18826            self.start_inline_blame_timer(window, cx);
18827        } else {
18828            self.show_git_blame_inline = true
18829        }
18830    }
18831
18832    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18833        self.blame.as_ref()
18834    }
18835
18836    pub fn show_git_blame_gutter(&self) -> bool {
18837        self.show_git_blame_gutter
18838    }
18839
18840    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18841        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18842    }
18843
18844    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18845        self.show_git_blame_inline
18846            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18847            && !self.newest_selection_head_on_empty_line(cx)
18848            && self.has_blame_entries(cx)
18849    }
18850
18851    fn has_blame_entries(&self, cx: &App) -> bool {
18852        self.blame()
18853            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18854    }
18855
18856    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18857        let cursor_anchor = self.selections.newest_anchor().head();
18858
18859        let snapshot = self.buffer.read(cx).snapshot(cx);
18860        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18861
18862        snapshot.line_len(buffer_row) == 0
18863    }
18864
18865    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18866        let buffer_and_selection = maybe!({
18867            let selection = self.selections.newest::<Point>(cx);
18868            let selection_range = selection.range();
18869
18870            let multi_buffer = self.buffer().read(cx);
18871            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18872            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18873
18874            let (buffer, range, _) = if selection.reversed {
18875                buffer_ranges.first()
18876            } else {
18877                buffer_ranges.last()
18878            }?;
18879
18880            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18881                ..text::ToPoint::to_point(&range.end, &buffer).row;
18882            Some((
18883                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18884                selection,
18885            ))
18886        });
18887
18888        let Some((buffer, selection)) = buffer_and_selection else {
18889            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18890        };
18891
18892        let Some(project) = self.project.as_ref() else {
18893            return Task::ready(Err(anyhow!("editor does not have project")));
18894        };
18895
18896        project.update(cx, |project, cx| {
18897            project.get_permalink_to_line(&buffer, selection, cx)
18898        })
18899    }
18900
18901    pub fn copy_permalink_to_line(
18902        &mut self,
18903        _: &CopyPermalinkToLine,
18904        window: &mut Window,
18905        cx: &mut Context<Self>,
18906    ) {
18907        let permalink_task = self.get_permalink_to_line(cx);
18908        let workspace = self.workspace();
18909
18910        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18911            Ok(permalink) => {
18912                cx.update(|_, cx| {
18913                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18914                })
18915                .ok();
18916            }
18917            Err(err) => {
18918                let message = format!("Failed to copy permalink: {err}");
18919
18920                anyhow::Result::<()>::Err(err).log_err();
18921
18922                if let Some(workspace) = workspace {
18923                    workspace
18924                        .update_in(cx, |workspace, _, cx| {
18925                            struct CopyPermalinkToLine;
18926
18927                            workspace.show_toast(
18928                                Toast::new(
18929                                    NotificationId::unique::<CopyPermalinkToLine>(),
18930                                    message,
18931                                ),
18932                                cx,
18933                            )
18934                        })
18935                        .ok();
18936                }
18937            }
18938        })
18939        .detach();
18940    }
18941
18942    pub fn copy_file_location(
18943        &mut self,
18944        _: &CopyFileLocation,
18945        _: &mut Window,
18946        cx: &mut Context<Self>,
18947    ) {
18948        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18949        if let Some(file) = self.target_file(cx) {
18950            if let Some(path) = file.path().to_str() {
18951                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18952            }
18953        }
18954    }
18955
18956    pub fn open_permalink_to_line(
18957        &mut self,
18958        _: &OpenPermalinkToLine,
18959        window: &mut Window,
18960        cx: &mut Context<Self>,
18961    ) {
18962        let permalink_task = self.get_permalink_to_line(cx);
18963        let workspace = self.workspace();
18964
18965        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18966            Ok(permalink) => {
18967                cx.update(|_, cx| {
18968                    cx.open_url(permalink.as_ref());
18969                })
18970                .ok();
18971            }
18972            Err(err) => {
18973                let message = format!("Failed to open permalink: {err}");
18974
18975                anyhow::Result::<()>::Err(err).log_err();
18976
18977                if let Some(workspace) = workspace {
18978                    workspace
18979                        .update(cx, |workspace, cx| {
18980                            struct OpenPermalinkToLine;
18981
18982                            workspace.show_toast(
18983                                Toast::new(
18984                                    NotificationId::unique::<OpenPermalinkToLine>(),
18985                                    message,
18986                                ),
18987                                cx,
18988                            )
18989                        })
18990                        .ok();
18991                }
18992            }
18993        })
18994        .detach();
18995    }
18996
18997    pub fn insert_uuid_v4(
18998        &mut self,
18999        _: &InsertUuidV4,
19000        window: &mut Window,
19001        cx: &mut Context<Self>,
19002    ) {
19003        self.insert_uuid(UuidVersion::V4, window, cx);
19004    }
19005
19006    pub fn insert_uuid_v7(
19007        &mut self,
19008        _: &InsertUuidV7,
19009        window: &mut Window,
19010        cx: &mut Context<Self>,
19011    ) {
19012        self.insert_uuid(UuidVersion::V7, window, cx);
19013    }
19014
19015    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19017        self.transact(window, cx, |this, window, cx| {
19018            let edits = this
19019                .selections
19020                .all::<Point>(cx)
19021                .into_iter()
19022                .map(|selection| {
19023                    let uuid = match version {
19024                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19025                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19026                    };
19027
19028                    (selection.range(), uuid.to_string())
19029                });
19030            this.edit(edits, cx);
19031            this.refresh_inline_completion(true, false, window, cx);
19032        });
19033    }
19034
19035    pub fn open_selections_in_multibuffer(
19036        &mut self,
19037        _: &OpenSelectionsInMultibuffer,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let multibuffer = self.buffer.read(cx);
19042
19043        let Some(buffer) = multibuffer.as_singleton() else {
19044            return;
19045        };
19046
19047        let Some(workspace) = self.workspace() else {
19048            return;
19049        };
19050
19051        let title = multibuffer.title(cx).to_string();
19052
19053        let locations = self
19054            .selections
19055            .all_anchors(cx)
19056            .into_iter()
19057            .map(|selection| Location {
19058                buffer: buffer.clone(),
19059                range: selection.start.text_anchor..selection.end.text_anchor,
19060            })
19061            .collect::<Vec<_>>();
19062
19063        cx.spawn_in(window, async move |_, cx| {
19064            workspace.update_in(cx, |workspace, window, cx| {
19065                Self::open_locations_in_multibuffer(
19066                    workspace,
19067                    locations,
19068                    format!("Selections for '{title}'"),
19069                    false,
19070                    MultibufferSelectionMode::All,
19071                    window,
19072                    cx,
19073                );
19074            })
19075        })
19076        .detach();
19077    }
19078
19079    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19080    /// last highlight added will be used.
19081    ///
19082    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19083    pub fn highlight_rows<T: 'static>(
19084        &mut self,
19085        range: Range<Anchor>,
19086        color: Hsla,
19087        options: RowHighlightOptions,
19088        cx: &mut Context<Self>,
19089    ) {
19090        let snapshot = self.buffer().read(cx).snapshot(cx);
19091        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19092        let ix = row_highlights.binary_search_by(|highlight| {
19093            Ordering::Equal
19094                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19095                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19096        });
19097
19098        if let Err(mut ix) = ix {
19099            let index = post_inc(&mut self.highlight_order);
19100
19101            // If this range intersects with the preceding highlight, then merge it with
19102            // the preceding highlight. Otherwise insert a new highlight.
19103            let mut merged = false;
19104            if ix > 0 {
19105                let prev_highlight = &mut row_highlights[ix - 1];
19106                if prev_highlight
19107                    .range
19108                    .end
19109                    .cmp(&range.start, &snapshot)
19110                    .is_ge()
19111                {
19112                    ix -= 1;
19113                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19114                        prev_highlight.range.end = range.end;
19115                    }
19116                    merged = true;
19117                    prev_highlight.index = index;
19118                    prev_highlight.color = color;
19119                    prev_highlight.options = options;
19120                }
19121            }
19122
19123            if !merged {
19124                row_highlights.insert(
19125                    ix,
19126                    RowHighlight {
19127                        range: range.clone(),
19128                        index,
19129                        color,
19130                        options,
19131                        type_id: TypeId::of::<T>(),
19132                    },
19133                );
19134            }
19135
19136            // If any of the following highlights intersect with this one, merge them.
19137            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19138                let highlight = &row_highlights[ix];
19139                if next_highlight
19140                    .range
19141                    .start
19142                    .cmp(&highlight.range.end, &snapshot)
19143                    .is_le()
19144                {
19145                    if next_highlight
19146                        .range
19147                        .end
19148                        .cmp(&highlight.range.end, &snapshot)
19149                        .is_gt()
19150                    {
19151                        row_highlights[ix].range.end = next_highlight.range.end;
19152                    }
19153                    row_highlights.remove(ix + 1);
19154                } else {
19155                    break;
19156                }
19157            }
19158        }
19159    }
19160
19161    /// Remove any highlighted row ranges of the given type that intersect the
19162    /// given ranges.
19163    pub fn remove_highlighted_rows<T: 'static>(
19164        &mut self,
19165        ranges_to_remove: Vec<Range<Anchor>>,
19166        cx: &mut Context<Self>,
19167    ) {
19168        let snapshot = self.buffer().read(cx).snapshot(cx);
19169        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19170        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19171        row_highlights.retain(|highlight| {
19172            while let Some(range_to_remove) = ranges_to_remove.peek() {
19173                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19174                    Ordering::Less | Ordering::Equal => {
19175                        ranges_to_remove.next();
19176                    }
19177                    Ordering::Greater => {
19178                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19179                            Ordering::Less | Ordering::Equal => {
19180                                return false;
19181                            }
19182                            Ordering::Greater => break,
19183                        }
19184                    }
19185                }
19186            }
19187
19188            true
19189        })
19190    }
19191
19192    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19193    pub fn clear_row_highlights<T: 'static>(&mut self) {
19194        self.highlighted_rows.remove(&TypeId::of::<T>());
19195    }
19196
19197    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19198    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19199        self.highlighted_rows
19200            .get(&TypeId::of::<T>())
19201            .map_or(&[] as &[_], |vec| vec.as_slice())
19202            .iter()
19203            .map(|highlight| (highlight.range.clone(), highlight.color))
19204    }
19205
19206    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19207    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19208    /// Allows to ignore certain kinds of highlights.
19209    pub fn highlighted_display_rows(
19210        &self,
19211        window: &mut Window,
19212        cx: &mut App,
19213    ) -> BTreeMap<DisplayRow, LineHighlight> {
19214        let snapshot = self.snapshot(window, cx);
19215        let mut used_highlight_orders = HashMap::default();
19216        self.highlighted_rows
19217            .iter()
19218            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19219            .fold(
19220                BTreeMap::<DisplayRow, LineHighlight>::new(),
19221                |mut unique_rows, highlight| {
19222                    let start = highlight.range.start.to_display_point(&snapshot);
19223                    let end = highlight.range.end.to_display_point(&snapshot);
19224                    let start_row = start.row().0;
19225                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19226                        && end.column() == 0
19227                    {
19228                        end.row().0.saturating_sub(1)
19229                    } else {
19230                        end.row().0
19231                    };
19232                    for row in start_row..=end_row {
19233                        let used_index =
19234                            used_highlight_orders.entry(row).or_insert(highlight.index);
19235                        if highlight.index >= *used_index {
19236                            *used_index = highlight.index;
19237                            unique_rows.insert(
19238                                DisplayRow(row),
19239                                LineHighlight {
19240                                    include_gutter: highlight.options.include_gutter,
19241                                    border: None,
19242                                    background: highlight.color.into(),
19243                                    type_id: Some(highlight.type_id),
19244                                },
19245                            );
19246                        }
19247                    }
19248                    unique_rows
19249                },
19250            )
19251    }
19252
19253    pub fn highlighted_display_row_for_autoscroll(
19254        &self,
19255        snapshot: &DisplaySnapshot,
19256    ) -> Option<DisplayRow> {
19257        self.highlighted_rows
19258            .values()
19259            .flat_map(|highlighted_rows| highlighted_rows.iter())
19260            .filter_map(|highlight| {
19261                if highlight.options.autoscroll {
19262                    Some(highlight.range.start.to_display_point(snapshot).row())
19263                } else {
19264                    None
19265                }
19266            })
19267            .min()
19268    }
19269
19270    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19271        self.highlight_background::<SearchWithinRange>(
19272            ranges,
19273            |colors| colors.colors().editor_document_highlight_read_background,
19274            cx,
19275        )
19276    }
19277
19278    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19279        self.breadcrumb_header = Some(new_header);
19280    }
19281
19282    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19283        self.clear_background_highlights::<SearchWithinRange>(cx);
19284    }
19285
19286    pub fn highlight_background<T: 'static>(
19287        &mut self,
19288        ranges: &[Range<Anchor>],
19289        color_fetcher: fn(&Theme) -> Hsla,
19290        cx: &mut Context<Self>,
19291    ) {
19292        self.background_highlights.insert(
19293            HighlightKey::Type(TypeId::of::<T>()),
19294            (color_fetcher, Arc::from(ranges)),
19295        );
19296        self.scrollbar_marker_state.dirty = true;
19297        cx.notify();
19298    }
19299
19300    pub fn highlight_background_key<T: 'static>(
19301        &mut self,
19302        key: usize,
19303        ranges: &[Range<Anchor>],
19304        color_fetcher: fn(&Theme) -> Hsla,
19305        cx: &mut Context<Self>,
19306    ) {
19307        self.background_highlights.insert(
19308            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19309            (color_fetcher, Arc::from(ranges)),
19310        );
19311        self.scrollbar_marker_state.dirty = true;
19312        cx.notify();
19313    }
19314
19315    pub fn clear_background_highlights<T: 'static>(
19316        &mut self,
19317        cx: &mut Context<Self>,
19318    ) -> Option<BackgroundHighlight> {
19319        let text_highlights = self
19320            .background_highlights
19321            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19322        if !text_highlights.1.is_empty() {
19323            self.scrollbar_marker_state.dirty = true;
19324            cx.notify();
19325        }
19326        Some(text_highlights)
19327    }
19328
19329    pub fn highlight_gutter<T: 'static>(
19330        &mut self,
19331        ranges: impl Into<Vec<Range<Anchor>>>,
19332        color_fetcher: fn(&App) -> Hsla,
19333        cx: &mut Context<Self>,
19334    ) {
19335        self.gutter_highlights
19336            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19337        cx.notify();
19338    }
19339
19340    pub fn clear_gutter_highlights<T: 'static>(
19341        &mut self,
19342        cx: &mut Context<Self>,
19343    ) -> Option<GutterHighlight> {
19344        cx.notify();
19345        self.gutter_highlights.remove(&TypeId::of::<T>())
19346    }
19347
19348    pub fn insert_gutter_highlight<T: 'static>(
19349        &mut self,
19350        range: Range<Anchor>,
19351        color_fetcher: fn(&App) -> Hsla,
19352        cx: &mut Context<Self>,
19353    ) {
19354        let snapshot = self.buffer().read(cx).snapshot(cx);
19355        let mut highlights = self
19356            .gutter_highlights
19357            .remove(&TypeId::of::<T>())
19358            .map(|(_, highlights)| highlights)
19359            .unwrap_or_default();
19360        let ix = highlights.binary_search_by(|highlight| {
19361            Ordering::Equal
19362                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19363                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19364        });
19365        if let Err(ix) = ix {
19366            highlights.insert(ix, range);
19367        }
19368        self.gutter_highlights
19369            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19370    }
19371
19372    pub fn remove_gutter_highlights<T: 'static>(
19373        &mut self,
19374        ranges_to_remove: Vec<Range<Anchor>>,
19375        cx: &mut Context<Self>,
19376    ) {
19377        let snapshot = self.buffer().read(cx).snapshot(cx);
19378        let Some((color_fetcher, mut gutter_highlights)) =
19379            self.gutter_highlights.remove(&TypeId::of::<T>())
19380        else {
19381            return;
19382        };
19383        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19384        gutter_highlights.retain(|highlight| {
19385            while let Some(range_to_remove) = ranges_to_remove.peek() {
19386                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19387                    Ordering::Less | Ordering::Equal => {
19388                        ranges_to_remove.next();
19389                    }
19390                    Ordering::Greater => {
19391                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19392                            Ordering::Less | Ordering::Equal => {
19393                                return false;
19394                            }
19395                            Ordering::Greater => break,
19396                        }
19397                    }
19398                }
19399            }
19400
19401            true
19402        });
19403        self.gutter_highlights
19404            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19405    }
19406
19407    #[cfg(feature = "test-support")]
19408    pub fn all_text_highlights(
19409        &self,
19410        window: &mut Window,
19411        cx: &mut Context<Self>,
19412    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19413        let snapshot = self.snapshot(window, cx);
19414        self.display_map.update(cx, |display_map, _| {
19415            display_map
19416                .all_text_highlights()
19417                .map(|highlight| {
19418                    let (style, ranges) = highlight.as_ref();
19419                    (
19420                        *style,
19421                        ranges
19422                            .iter()
19423                            .map(|range| range.clone().to_display_points(&snapshot))
19424                            .collect(),
19425                    )
19426                })
19427                .collect()
19428        })
19429    }
19430
19431    #[cfg(feature = "test-support")]
19432    pub fn all_text_background_highlights(
19433        &self,
19434        window: &mut Window,
19435        cx: &mut Context<Self>,
19436    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19437        let snapshot = self.snapshot(window, cx);
19438        let buffer = &snapshot.buffer_snapshot;
19439        let start = buffer.anchor_before(0);
19440        let end = buffer.anchor_after(buffer.len());
19441        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19442    }
19443
19444    #[cfg(feature = "test-support")]
19445    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19446        let snapshot = self.buffer().read(cx).snapshot(cx);
19447
19448        let highlights = self
19449            .background_highlights
19450            .get(&HighlightKey::Type(TypeId::of::<
19451                items::BufferSearchHighlights,
19452            >()));
19453
19454        if let Some((_color, ranges)) = highlights {
19455            ranges
19456                .iter()
19457                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19458                .collect_vec()
19459        } else {
19460            vec![]
19461        }
19462    }
19463
19464    fn document_highlights_for_position<'a>(
19465        &'a self,
19466        position: Anchor,
19467        buffer: &'a MultiBufferSnapshot,
19468    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19469        let read_highlights = self
19470            .background_highlights
19471            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19472            .map(|h| &h.1);
19473        let write_highlights = self
19474            .background_highlights
19475            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19476            .map(|h| &h.1);
19477        let left_position = position.bias_left(buffer);
19478        let right_position = position.bias_right(buffer);
19479        read_highlights
19480            .into_iter()
19481            .chain(write_highlights)
19482            .flat_map(move |ranges| {
19483                let start_ix = match ranges.binary_search_by(|probe| {
19484                    let cmp = probe.end.cmp(&left_position, buffer);
19485                    if cmp.is_ge() {
19486                        Ordering::Greater
19487                    } else {
19488                        Ordering::Less
19489                    }
19490                }) {
19491                    Ok(i) | Err(i) => i,
19492                };
19493
19494                ranges[start_ix..]
19495                    .iter()
19496                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19497            })
19498    }
19499
19500    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19501        self.background_highlights
19502            .get(&HighlightKey::Type(TypeId::of::<T>()))
19503            .map_or(false, |(_, highlights)| !highlights.is_empty())
19504    }
19505
19506    pub fn background_highlights_in_range(
19507        &self,
19508        search_range: Range<Anchor>,
19509        display_snapshot: &DisplaySnapshot,
19510        theme: &Theme,
19511    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19512        let mut results = Vec::new();
19513        for (color_fetcher, ranges) in self.background_highlights.values() {
19514            let color = color_fetcher(theme);
19515            let start_ix = match ranges.binary_search_by(|probe| {
19516                let cmp = probe
19517                    .end
19518                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19519                if cmp.is_gt() {
19520                    Ordering::Greater
19521                } else {
19522                    Ordering::Less
19523                }
19524            }) {
19525                Ok(i) | Err(i) => i,
19526            };
19527            for range in &ranges[start_ix..] {
19528                if range
19529                    .start
19530                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19531                    .is_ge()
19532                {
19533                    break;
19534                }
19535
19536                let start = range.start.to_display_point(display_snapshot);
19537                let end = range.end.to_display_point(display_snapshot);
19538                results.push((start..end, color))
19539            }
19540        }
19541        results
19542    }
19543
19544    pub fn background_highlight_row_ranges<T: 'static>(
19545        &self,
19546        search_range: Range<Anchor>,
19547        display_snapshot: &DisplaySnapshot,
19548        count: usize,
19549    ) -> Vec<RangeInclusive<DisplayPoint>> {
19550        let mut results = Vec::new();
19551        let Some((_, ranges)) = self
19552            .background_highlights
19553            .get(&HighlightKey::Type(TypeId::of::<T>()))
19554        else {
19555            return vec![];
19556        };
19557
19558        let start_ix = match ranges.binary_search_by(|probe| {
19559            let cmp = probe
19560                .end
19561                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19562            if cmp.is_gt() {
19563                Ordering::Greater
19564            } else {
19565                Ordering::Less
19566            }
19567        }) {
19568            Ok(i) | Err(i) => i,
19569        };
19570        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19571            if let (Some(start_display), Some(end_display)) = (start, end) {
19572                results.push(
19573                    start_display.to_display_point(display_snapshot)
19574                        ..=end_display.to_display_point(display_snapshot),
19575                );
19576            }
19577        };
19578        let mut start_row: Option<Point> = None;
19579        let mut end_row: Option<Point> = None;
19580        if ranges.len() > count {
19581            return Vec::new();
19582        }
19583        for range in &ranges[start_ix..] {
19584            if range
19585                .start
19586                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19587                .is_ge()
19588            {
19589                break;
19590            }
19591            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19592            if let Some(current_row) = &end_row {
19593                if end.row == current_row.row {
19594                    continue;
19595                }
19596            }
19597            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19598            if start_row.is_none() {
19599                assert_eq!(end_row, None);
19600                start_row = Some(start);
19601                end_row = Some(end);
19602                continue;
19603            }
19604            if let Some(current_end) = end_row.as_mut() {
19605                if start.row > current_end.row + 1 {
19606                    push_region(start_row, end_row);
19607                    start_row = Some(start);
19608                    end_row = Some(end);
19609                } else {
19610                    // Merge two hunks.
19611                    *current_end = end;
19612                }
19613            } else {
19614                unreachable!();
19615            }
19616        }
19617        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19618        push_region(start_row, end_row);
19619        results
19620    }
19621
19622    pub fn gutter_highlights_in_range(
19623        &self,
19624        search_range: Range<Anchor>,
19625        display_snapshot: &DisplaySnapshot,
19626        cx: &App,
19627    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19628        let mut results = Vec::new();
19629        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19630            let color = color_fetcher(cx);
19631            let start_ix = match ranges.binary_search_by(|probe| {
19632                let cmp = probe
19633                    .end
19634                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19635                if cmp.is_gt() {
19636                    Ordering::Greater
19637                } else {
19638                    Ordering::Less
19639                }
19640            }) {
19641                Ok(i) | Err(i) => i,
19642            };
19643            for range in &ranges[start_ix..] {
19644                if range
19645                    .start
19646                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19647                    .is_ge()
19648                {
19649                    break;
19650                }
19651
19652                let start = range.start.to_display_point(display_snapshot);
19653                let end = range.end.to_display_point(display_snapshot);
19654                results.push((start..end, color))
19655            }
19656        }
19657        results
19658    }
19659
19660    /// Get the text ranges corresponding to the redaction query
19661    pub fn redacted_ranges(
19662        &self,
19663        search_range: Range<Anchor>,
19664        display_snapshot: &DisplaySnapshot,
19665        cx: &App,
19666    ) -> Vec<Range<DisplayPoint>> {
19667        display_snapshot
19668            .buffer_snapshot
19669            .redacted_ranges(search_range, |file| {
19670                if let Some(file) = file {
19671                    file.is_private()
19672                        && EditorSettings::get(
19673                            Some(SettingsLocation {
19674                                worktree_id: file.worktree_id(cx),
19675                                path: file.path().as_ref(),
19676                            }),
19677                            cx,
19678                        )
19679                        .redact_private_values
19680                } else {
19681                    false
19682                }
19683            })
19684            .map(|range| {
19685                range.start.to_display_point(display_snapshot)
19686                    ..range.end.to_display_point(display_snapshot)
19687            })
19688            .collect()
19689    }
19690
19691    pub fn highlight_text_key<T: 'static>(
19692        &mut self,
19693        key: usize,
19694        ranges: Vec<Range<Anchor>>,
19695        style: HighlightStyle,
19696        cx: &mut Context<Self>,
19697    ) {
19698        self.display_map.update(cx, |map, _| {
19699            map.highlight_text(
19700                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19701                ranges,
19702                style,
19703            );
19704        });
19705        cx.notify();
19706    }
19707
19708    pub fn highlight_text<T: 'static>(
19709        &mut self,
19710        ranges: Vec<Range<Anchor>>,
19711        style: HighlightStyle,
19712        cx: &mut Context<Self>,
19713    ) {
19714        self.display_map.update(cx, |map, _| {
19715            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19716        });
19717        cx.notify();
19718    }
19719
19720    pub(crate) fn highlight_inlays<T: 'static>(
19721        &mut self,
19722        highlights: Vec<InlayHighlight>,
19723        style: HighlightStyle,
19724        cx: &mut Context<Self>,
19725    ) {
19726        self.display_map.update(cx, |map, _| {
19727            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19728        });
19729        cx.notify();
19730    }
19731
19732    pub fn text_highlights<'a, T: 'static>(
19733        &'a self,
19734        cx: &'a App,
19735    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19736        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19737    }
19738
19739    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19740        let cleared = self
19741            .display_map
19742            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19743        if cleared {
19744            cx.notify();
19745        }
19746    }
19747
19748    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19749        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19750            && self.focus_handle.is_focused(window)
19751    }
19752
19753    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19754        self.show_cursor_when_unfocused = is_enabled;
19755        cx.notify();
19756    }
19757
19758    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19759        cx.notify();
19760    }
19761
19762    fn on_debug_session_event(
19763        &mut self,
19764        _session: Entity<Session>,
19765        event: &SessionEvent,
19766        cx: &mut Context<Self>,
19767    ) {
19768        match event {
19769            SessionEvent::InvalidateInlineValue => {
19770                self.refresh_inline_values(cx);
19771            }
19772            _ => {}
19773        }
19774    }
19775
19776    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19777        let Some(project) = self.project.clone() else {
19778            return;
19779        };
19780
19781        if !self.inline_value_cache.enabled {
19782            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19783            self.splice_inlays(&inlays, Vec::new(), cx);
19784            return;
19785        }
19786
19787        let current_execution_position = self
19788            .highlighted_rows
19789            .get(&TypeId::of::<ActiveDebugLine>())
19790            .and_then(|lines| lines.last().map(|line| line.range.end));
19791
19792        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19793            let inline_values = editor
19794                .update(cx, |editor, cx| {
19795                    let Some(current_execution_position) = current_execution_position else {
19796                        return Some(Task::ready(Ok(Vec::new())));
19797                    };
19798
19799                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19800                        let snapshot = buffer.snapshot(cx);
19801
19802                        let excerpt = snapshot.excerpt_containing(
19803                            current_execution_position..current_execution_position,
19804                        )?;
19805
19806                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19807                    })?;
19808
19809                    let range =
19810                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19811
19812                    project.inline_values(buffer, range, cx)
19813                })
19814                .ok()
19815                .flatten()?
19816                .await
19817                .context("refreshing debugger inlays")
19818                .log_err()?;
19819
19820            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19821
19822            for (buffer_id, inline_value) in inline_values
19823                .into_iter()
19824                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19825            {
19826                buffer_inline_values
19827                    .entry(buffer_id)
19828                    .or_default()
19829                    .push(inline_value);
19830            }
19831
19832            editor
19833                .update(cx, |editor, cx| {
19834                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19835                    let mut new_inlays = Vec::default();
19836
19837                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19838                        let buffer_id = buffer_snapshot.remote_id();
19839                        buffer_inline_values
19840                            .get(&buffer_id)
19841                            .into_iter()
19842                            .flatten()
19843                            .for_each(|hint| {
19844                                let inlay = Inlay::debugger(
19845                                    post_inc(&mut editor.next_inlay_id),
19846                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19847                                    hint.text(),
19848                                );
19849                                if !inlay.text.chars().contains(&'\n') {
19850                                    new_inlays.push(inlay);
19851                                }
19852                            });
19853                    }
19854
19855                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19856                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19857
19858                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19859                })
19860                .ok()?;
19861            Some(())
19862        });
19863    }
19864
19865    fn on_buffer_event(
19866        &mut self,
19867        multibuffer: &Entity<MultiBuffer>,
19868        event: &multi_buffer::Event,
19869        window: &mut Window,
19870        cx: &mut Context<Self>,
19871    ) {
19872        match event {
19873            multi_buffer::Event::Edited {
19874                singleton_buffer_edited,
19875                edited_buffer,
19876            } => {
19877                self.scrollbar_marker_state.dirty = true;
19878                self.active_indent_guides_state.dirty = true;
19879                self.refresh_active_diagnostics(cx);
19880                self.refresh_code_actions(window, cx);
19881                self.refresh_selected_text_highlights(true, window, cx);
19882                self.refresh_single_line_folds(window, cx);
19883                refresh_matching_bracket_highlights(self, window, cx);
19884                if self.has_active_inline_completion() {
19885                    self.update_visible_inline_completion(window, cx);
19886                }
19887                if let Some(project) = self.project.as_ref() {
19888                    if let Some(edited_buffer) = edited_buffer {
19889                        project.update(cx, |project, cx| {
19890                            self.registered_buffers
19891                                .entry(edited_buffer.read(cx).remote_id())
19892                                .or_insert_with(|| {
19893                                    project
19894                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19895                                });
19896                        });
19897                    }
19898                }
19899                cx.emit(EditorEvent::BufferEdited);
19900                cx.emit(SearchEvent::MatchesInvalidated);
19901
19902                if let Some(buffer) = edited_buffer {
19903                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19904                }
19905
19906                if *singleton_buffer_edited {
19907                    if let Some(buffer) = edited_buffer {
19908                        if buffer.read(cx).file().is_none() {
19909                            cx.emit(EditorEvent::TitleChanged);
19910                        }
19911                    }
19912                    if let Some(project) = &self.project {
19913                        #[allow(clippy::mutable_key_type)]
19914                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19915                            multibuffer
19916                                .all_buffers()
19917                                .into_iter()
19918                                .filter_map(|buffer| {
19919                                    buffer.update(cx, |buffer, cx| {
19920                                        let language = buffer.language()?;
19921                                        let should_discard = project.update(cx, |project, cx| {
19922                                            project.is_local()
19923                                                && !project.has_language_servers_for(buffer, cx)
19924                                        });
19925                                        should_discard.not().then_some(language.clone())
19926                                    })
19927                                })
19928                                .collect::<HashSet<_>>()
19929                        });
19930                        if !languages_affected.is_empty() {
19931                            self.refresh_inlay_hints(
19932                                InlayHintRefreshReason::BufferEdited(languages_affected),
19933                                cx,
19934                            );
19935                        }
19936                    }
19937                }
19938
19939                let Some(project) = &self.project else { return };
19940                let (telemetry, is_via_ssh) = {
19941                    let project = project.read(cx);
19942                    let telemetry = project.client().telemetry().clone();
19943                    let is_via_ssh = project.is_via_ssh();
19944                    (telemetry, is_via_ssh)
19945                };
19946                refresh_linked_ranges(self, window, cx);
19947                telemetry.log_edit_event("editor", is_via_ssh);
19948            }
19949            multi_buffer::Event::ExcerptsAdded {
19950                buffer,
19951                predecessor,
19952                excerpts,
19953            } => {
19954                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19955                let buffer_id = buffer.read(cx).remote_id();
19956                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19957                    if let Some(project) = &self.project {
19958                        update_uncommitted_diff_for_buffer(
19959                            cx.entity(),
19960                            project,
19961                            [buffer.clone()],
19962                            self.buffer.clone(),
19963                            cx,
19964                        )
19965                        .detach();
19966                    }
19967                }
19968                self.update_lsp_data(false, Some(buffer_id), window, cx);
19969                cx.emit(EditorEvent::ExcerptsAdded {
19970                    buffer: buffer.clone(),
19971                    predecessor: *predecessor,
19972                    excerpts: excerpts.clone(),
19973                });
19974                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19975            }
19976            multi_buffer::Event::ExcerptsRemoved {
19977                ids,
19978                removed_buffer_ids,
19979            } => {
19980                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19981                let buffer = self.buffer.read(cx);
19982                self.registered_buffers
19983                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19984                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19985                cx.emit(EditorEvent::ExcerptsRemoved {
19986                    ids: ids.clone(),
19987                    removed_buffer_ids: removed_buffer_ids.clone(),
19988                });
19989            }
19990            multi_buffer::Event::ExcerptsEdited {
19991                excerpt_ids,
19992                buffer_ids,
19993            } => {
19994                self.display_map.update(cx, |map, cx| {
19995                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19996                });
19997                cx.emit(EditorEvent::ExcerptsEdited {
19998                    ids: excerpt_ids.clone(),
19999                });
20000            }
20001            multi_buffer::Event::ExcerptsExpanded { ids } => {
20002                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20003                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20004            }
20005            multi_buffer::Event::Reparsed(buffer_id) => {
20006                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20007                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20008
20009                cx.emit(EditorEvent::Reparsed(*buffer_id));
20010            }
20011            multi_buffer::Event::DiffHunksToggled => {
20012                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20013            }
20014            multi_buffer::Event::LanguageChanged(buffer_id) => {
20015                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20016                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20017                cx.emit(EditorEvent::Reparsed(*buffer_id));
20018                cx.notify();
20019            }
20020            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20021            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20022            multi_buffer::Event::FileHandleChanged
20023            | multi_buffer::Event::Reloaded
20024            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20025            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20026            multi_buffer::Event::DiagnosticsUpdated => {
20027                self.update_diagnostics_state(window, cx);
20028            }
20029            _ => {}
20030        };
20031    }
20032
20033    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20034        if !self.diagnostics_enabled() {
20035            return;
20036        }
20037        self.refresh_active_diagnostics(cx);
20038        self.refresh_inline_diagnostics(true, window, cx);
20039        self.scrollbar_marker_state.dirty = true;
20040        cx.notify();
20041    }
20042
20043    pub fn start_temporary_diff_override(&mut self) {
20044        self.load_diff_task.take();
20045        self.temporary_diff_override = true;
20046    }
20047
20048    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20049        self.temporary_diff_override = false;
20050        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20051        self.buffer.update(cx, |buffer, cx| {
20052            buffer.set_all_diff_hunks_collapsed(cx);
20053        });
20054
20055        if let Some(project) = self.project.clone() {
20056            self.load_diff_task = Some(
20057                update_uncommitted_diff_for_buffer(
20058                    cx.entity(),
20059                    &project,
20060                    self.buffer.read(cx).all_buffers(),
20061                    self.buffer.clone(),
20062                    cx,
20063                )
20064                .shared(),
20065            );
20066        }
20067    }
20068
20069    fn on_display_map_changed(
20070        &mut self,
20071        _: Entity<DisplayMap>,
20072        _: &mut Window,
20073        cx: &mut Context<Self>,
20074    ) {
20075        cx.notify();
20076    }
20077
20078    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20079        if self.diagnostics_enabled() {
20080            let new_severity = EditorSettings::get_global(cx)
20081                .diagnostics_max_severity
20082                .unwrap_or(DiagnosticSeverity::Hint);
20083            self.set_max_diagnostics_severity(new_severity, cx);
20084        }
20085        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20086        self.update_edit_prediction_settings(cx);
20087        self.refresh_inline_completion(true, false, window, cx);
20088        self.refresh_inline_values(cx);
20089        self.refresh_inlay_hints(
20090            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20091                self.selections.newest_anchor().head(),
20092                &self.buffer.read(cx).snapshot(cx),
20093                cx,
20094            )),
20095            cx,
20096        );
20097
20098        let old_cursor_shape = self.cursor_shape;
20099
20100        {
20101            let editor_settings = EditorSettings::get_global(cx);
20102            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20103            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20104            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20105            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20106        }
20107
20108        if old_cursor_shape != self.cursor_shape {
20109            cx.emit(EditorEvent::CursorShapeChanged);
20110        }
20111
20112        let project_settings = ProjectSettings::get_global(cx);
20113        self.serialize_dirty_buffers =
20114            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20115
20116        if self.mode.is_full() {
20117            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20118            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20119            if self.show_inline_diagnostics != show_inline_diagnostics {
20120                self.show_inline_diagnostics = show_inline_diagnostics;
20121                self.refresh_inline_diagnostics(false, window, cx);
20122            }
20123
20124            if self.git_blame_inline_enabled != inline_blame_enabled {
20125                self.toggle_git_blame_inline_internal(false, window, cx);
20126            }
20127
20128            let minimap_settings = EditorSettings::get_global(cx).minimap;
20129            if self.minimap_visibility != MinimapVisibility::Disabled {
20130                if self.minimap_visibility.settings_visibility()
20131                    != minimap_settings.minimap_enabled()
20132                {
20133                    self.set_minimap_visibility(
20134                        MinimapVisibility::for_mode(self.mode(), cx),
20135                        window,
20136                        cx,
20137                    );
20138                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20139                    minimap_entity.update(cx, |minimap_editor, cx| {
20140                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20141                    })
20142                }
20143            }
20144        }
20145
20146        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20147            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20148        }) {
20149            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20150                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20151            }
20152            self.refresh_colors(false, None, window, cx);
20153        }
20154
20155        cx.notify();
20156    }
20157
20158    pub fn set_searchable(&mut self, searchable: bool) {
20159        self.searchable = searchable;
20160    }
20161
20162    pub fn searchable(&self) -> bool {
20163        self.searchable
20164    }
20165
20166    fn open_proposed_changes_editor(
20167        &mut self,
20168        _: &OpenProposedChangesEditor,
20169        window: &mut Window,
20170        cx: &mut Context<Self>,
20171    ) {
20172        let Some(workspace) = self.workspace() else {
20173            cx.propagate();
20174            return;
20175        };
20176
20177        let selections = self.selections.all::<usize>(cx);
20178        let multi_buffer = self.buffer.read(cx);
20179        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20180        let mut new_selections_by_buffer = HashMap::default();
20181        for selection in selections {
20182            for (buffer, range, _) in
20183                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20184            {
20185                let mut range = range.to_point(buffer);
20186                range.start.column = 0;
20187                range.end.column = buffer.line_len(range.end.row);
20188                new_selections_by_buffer
20189                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20190                    .or_insert(Vec::new())
20191                    .push(range)
20192            }
20193        }
20194
20195        let proposed_changes_buffers = new_selections_by_buffer
20196            .into_iter()
20197            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20198            .collect::<Vec<_>>();
20199        let proposed_changes_editor = cx.new(|cx| {
20200            ProposedChangesEditor::new(
20201                "Proposed changes",
20202                proposed_changes_buffers,
20203                self.project.clone(),
20204                window,
20205                cx,
20206            )
20207        });
20208
20209        window.defer(cx, move |window, cx| {
20210            workspace.update(cx, |workspace, cx| {
20211                workspace.active_pane().update(cx, |pane, cx| {
20212                    pane.add_item(
20213                        Box::new(proposed_changes_editor),
20214                        true,
20215                        true,
20216                        None,
20217                        window,
20218                        cx,
20219                    );
20220                });
20221            });
20222        });
20223    }
20224
20225    pub fn open_excerpts_in_split(
20226        &mut self,
20227        _: &OpenExcerptsSplit,
20228        window: &mut Window,
20229        cx: &mut Context<Self>,
20230    ) {
20231        self.open_excerpts_common(None, true, window, cx)
20232    }
20233
20234    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20235        self.open_excerpts_common(None, false, window, cx)
20236    }
20237
20238    fn open_excerpts_common(
20239        &mut self,
20240        jump_data: Option<JumpData>,
20241        split: bool,
20242        window: &mut Window,
20243        cx: &mut Context<Self>,
20244    ) {
20245        let Some(workspace) = self.workspace() else {
20246            cx.propagate();
20247            return;
20248        };
20249
20250        if self.buffer.read(cx).is_singleton() {
20251            cx.propagate();
20252            return;
20253        }
20254
20255        let mut new_selections_by_buffer = HashMap::default();
20256        match &jump_data {
20257            Some(JumpData::MultiBufferPoint {
20258                excerpt_id,
20259                position,
20260                anchor,
20261                line_offset_from_top,
20262            }) => {
20263                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20264                if let Some(buffer) = multi_buffer_snapshot
20265                    .buffer_id_for_excerpt(*excerpt_id)
20266                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20267                {
20268                    let buffer_snapshot = buffer.read(cx).snapshot();
20269                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20270                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20271                    } else {
20272                        buffer_snapshot.clip_point(*position, Bias::Left)
20273                    };
20274                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20275                    new_selections_by_buffer.insert(
20276                        buffer,
20277                        (
20278                            vec![jump_to_offset..jump_to_offset],
20279                            Some(*line_offset_from_top),
20280                        ),
20281                    );
20282                }
20283            }
20284            Some(JumpData::MultiBufferRow {
20285                row,
20286                line_offset_from_top,
20287            }) => {
20288                let point = MultiBufferPoint::new(row.0, 0);
20289                if let Some((buffer, buffer_point, _)) =
20290                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20291                {
20292                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20293                    new_selections_by_buffer
20294                        .entry(buffer)
20295                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20296                        .0
20297                        .push(buffer_offset..buffer_offset)
20298                }
20299            }
20300            None => {
20301                let selections = self.selections.all::<usize>(cx);
20302                let multi_buffer = self.buffer.read(cx);
20303                for selection in selections {
20304                    for (snapshot, range, _, anchor) in multi_buffer
20305                        .snapshot(cx)
20306                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20307                    {
20308                        if let Some(anchor) = anchor {
20309                            // selection is in a deleted hunk
20310                            let Some(buffer_id) = anchor.buffer_id else {
20311                                continue;
20312                            };
20313                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20314                                continue;
20315                            };
20316                            let offset = text::ToOffset::to_offset(
20317                                &anchor.text_anchor,
20318                                &buffer_handle.read(cx).snapshot(),
20319                            );
20320                            let range = offset..offset;
20321                            new_selections_by_buffer
20322                                .entry(buffer_handle)
20323                                .or_insert((Vec::new(), None))
20324                                .0
20325                                .push(range)
20326                        } else {
20327                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20328                            else {
20329                                continue;
20330                            };
20331                            new_selections_by_buffer
20332                                .entry(buffer_handle)
20333                                .or_insert((Vec::new(), None))
20334                                .0
20335                                .push(range)
20336                        }
20337                    }
20338                }
20339            }
20340        }
20341
20342        new_selections_by_buffer
20343            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20344
20345        if new_selections_by_buffer.is_empty() {
20346            return;
20347        }
20348
20349        // We defer the pane interaction because we ourselves are a workspace item
20350        // and activating a new item causes the pane to call a method on us reentrantly,
20351        // which panics if we're on the stack.
20352        window.defer(cx, move |window, cx| {
20353            workspace.update(cx, |workspace, cx| {
20354                let pane = if split {
20355                    workspace.adjacent_pane(window, cx)
20356                } else {
20357                    workspace.active_pane().clone()
20358                };
20359
20360                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20361                    let editor = buffer
20362                        .read(cx)
20363                        .file()
20364                        .is_none()
20365                        .then(|| {
20366                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20367                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20368                            // Instead, we try to activate the existing editor in the pane first.
20369                            let (editor, pane_item_index) =
20370                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20371                                    let editor = item.downcast::<Editor>()?;
20372                                    let singleton_buffer =
20373                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20374                                    if singleton_buffer == buffer {
20375                                        Some((editor, i))
20376                                    } else {
20377                                        None
20378                                    }
20379                                })?;
20380                            pane.update(cx, |pane, cx| {
20381                                pane.activate_item(pane_item_index, true, true, window, cx)
20382                            });
20383                            Some(editor)
20384                        })
20385                        .flatten()
20386                        .unwrap_or_else(|| {
20387                            workspace.open_project_item::<Self>(
20388                                pane.clone(),
20389                                buffer,
20390                                true,
20391                                true,
20392                                window,
20393                                cx,
20394                            )
20395                        });
20396
20397                    editor.update(cx, |editor, cx| {
20398                        let autoscroll = match scroll_offset {
20399                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20400                            None => Autoscroll::newest(),
20401                        };
20402                        let nav_history = editor.nav_history.take();
20403                        editor.change_selections(
20404                            SelectionEffects::scroll(autoscroll),
20405                            window,
20406                            cx,
20407                            |s| {
20408                                s.select_ranges(ranges);
20409                            },
20410                        );
20411                        editor.nav_history = nav_history;
20412                    });
20413                }
20414            })
20415        });
20416    }
20417
20418    // For now, don't allow opening excerpts in buffers that aren't backed by
20419    // regular project files.
20420    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20421        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20422    }
20423
20424    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20425        let snapshot = self.buffer.read(cx).read(cx);
20426        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20427        Some(
20428            ranges
20429                .iter()
20430                .map(move |range| {
20431                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20432                })
20433                .collect(),
20434        )
20435    }
20436
20437    fn selection_replacement_ranges(
20438        &self,
20439        range: Range<OffsetUtf16>,
20440        cx: &mut App,
20441    ) -> Vec<Range<OffsetUtf16>> {
20442        let selections = self.selections.all::<OffsetUtf16>(cx);
20443        let newest_selection = selections
20444            .iter()
20445            .max_by_key(|selection| selection.id)
20446            .unwrap();
20447        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20448        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20449        let snapshot = self.buffer.read(cx).read(cx);
20450        selections
20451            .into_iter()
20452            .map(|mut selection| {
20453                selection.start.0 =
20454                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20455                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20456                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20457                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20458            })
20459            .collect()
20460    }
20461
20462    fn report_editor_event(
20463        &self,
20464        event_type: &'static str,
20465        file_extension: Option<String>,
20466        cx: &App,
20467    ) {
20468        if cfg!(any(test, feature = "test-support")) {
20469            return;
20470        }
20471
20472        let Some(project) = &self.project else { return };
20473
20474        // If None, we are in a file without an extension
20475        let file = self
20476            .buffer
20477            .read(cx)
20478            .as_singleton()
20479            .and_then(|b| b.read(cx).file());
20480        let file_extension = file_extension.or(file
20481            .as_ref()
20482            .and_then(|file| Path::new(file.file_name(cx)).extension())
20483            .and_then(|e| e.to_str())
20484            .map(|a| a.to_string()));
20485
20486        let vim_mode = vim_enabled(cx);
20487
20488        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20489        let copilot_enabled = edit_predictions_provider
20490            == language::language_settings::EditPredictionProvider::Copilot;
20491        let copilot_enabled_for_language = self
20492            .buffer
20493            .read(cx)
20494            .language_settings(cx)
20495            .show_edit_predictions;
20496
20497        let project = project.read(cx);
20498        telemetry::event!(
20499            event_type,
20500            file_extension,
20501            vim_mode,
20502            copilot_enabled,
20503            copilot_enabled_for_language,
20504            edit_predictions_provider,
20505            is_via_ssh = project.is_via_ssh(),
20506        );
20507    }
20508
20509    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20510    /// with each line being an array of {text, highlight} objects.
20511    fn copy_highlight_json(
20512        &mut self,
20513        _: &CopyHighlightJson,
20514        window: &mut Window,
20515        cx: &mut Context<Self>,
20516    ) {
20517        #[derive(Serialize)]
20518        struct Chunk<'a> {
20519            text: String,
20520            highlight: Option<&'a str>,
20521        }
20522
20523        let snapshot = self.buffer.read(cx).snapshot(cx);
20524        let range = self
20525            .selected_text_range(false, window, cx)
20526            .and_then(|selection| {
20527                if selection.range.is_empty() {
20528                    None
20529                } else {
20530                    Some(selection.range)
20531                }
20532            })
20533            .unwrap_or_else(|| 0..snapshot.len());
20534
20535        let chunks = snapshot.chunks(range, true);
20536        let mut lines = Vec::new();
20537        let mut line: VecDeque<Chunk> = VecDeque::new();
20538
20539        let Some(style) = self.style.as_ref() else {
20540            return;
20541        };
20542
20543        for chunk in chunks {
20544            let highlight = chunk
20545                .syntax_highlight_id
20546                .and_then(|id| id.name(&style.syntax));
20547            let mut chunk_lines = chunk.text.split('\n').peekable();
20548            while let Some(text) = chunk_lines.next() {
20549                let mut merged_with_last_token = false;
20550                if let Some(last_token) = line.back_mut() {
20551                    if last_token.highlight == highlight {
20552                        last_token.text.push_str(text);
20553                        merged_with_last_token = true;
20554                    }
20555                }
20556
20557                if !merged_with_last_token {
20558                    line.push_back(Chunk {
20559                        text: text.into(),
20560                        highlight,
20561                    });
20562                }
20563
20564                if chunk_lines.peek().is_some() {
20565                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20566                        line.pop_front();
20567                    }
20568                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20569                        line.pop_back();
20570                    }
20571
20572                    lines.push(mem::take(&mut line));
20573                }
20574            }
20575        }
20576
20577        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20578            return;
20579        };
20580        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20581    }
20582
20583    pub fn open_context_menu(
20584        &mut self,
20585        _: &OpenContextMenu,
20586        window: &mut Window,
20587        cx: &mut Context<Self>,
20588    ) {
20589        self.request_autoscroll(Autoscroll::newest(), cx);
20590        let position = self.selections.newest_display(cx).start;
20591        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20592    }
20593
20594    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20595        &self.inlay_hint_cache
20596    }
20597
20598    pub fn replay_insert_event(
20599        &mut self,
20600        text: &str,
20601        relative_utf16_range: Option<Range<isize>>,
20602        window: &mut Window,
20603        cx: &mut Context<Self>,
20604    ) {
20605        if !self.input_enabled {
20606            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20607            return;
20608        }
20609        if let Some(relative_utf16_range) = relative_utf16_range {
20610            let selections = self.selections.all::<OffsetUtf16>(cx);
20611            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20612                let new_ranges = selections.into_iter().map(|range| {
20613                    let start = OffsetUtf16(
20614                        range
20615                            .head()
20616                            .0
20617                            .saturating_add_signed(relative_utf16_range.start),
20618                    );
20619                    let end = OffsetUtf16(
20620                        range
20621                            .head()
20622                            .0
20623                            .saturating_add_signed(relative_utf16_range.end),
20624                    );
20625                    start..end
20626                });
20627                s.select_ranges(new_ranges);
20628            });
20629        }
20630
20631        self.handle_input(text, window, cx);
20632    }
20633
20634    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20635        let Some(provider) = self.semantics_provider.as_ref() else {
20636            return false;
20637        };
20638
20639        let mut supports = false;
20640        self.buffer().update(cx, |this, cx| {
20641            this.for_each_buffer(|buffer| {
20642                supports |= provider.supports_inlay_hints(buffer, cx);
20643            });
20644        });
20645
20646        supports
20647    }
20648
20649    pub fn is_focused(&self, window: &Window) -> bool {
20650        self.focus_handle.is_focused(window)
20651    }
20652
20653    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20654        cx.emit(EditorEvent::Focused);
20655
20656        if let Some(descendant) = self
20657            .last_focused_descendant
20658            .take()
20659            .and_then(|descendant| descendant.upgrade())
20660        {
20661            window.focus(&descendant);
20662        } else {
20663            if let Some(blame) = self.blame.as_ref() {
20664                blame.update(cx, GitBlame::focus)
20665            }
20666
20667            self.blink_manager.update(cx, BlinkManager::enable);
20668            self.show_cursor_names(window, cx);
20669            self.buffer.update(cx, |buffer, cx| {
20670                buffer.finalize_last_transaction(cx);
20671                if self.leader_id.is_none() {
20672                    buffer.set_active_selections(
20673                        &self.selections.disjoint_anchors(),
20674                        self.selections.line_mode,
20675                        self.cursor_shape,
20676                        cx,
20677                    );
20678                }
20679            });
20680        }
20681    }
20682
20683    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20684        cx.emit(EditorEvent::FocusedIn)
20685    }
20686
20687    fn handle_focus_out(
20688        &mut self,
20689        event: FocusOutEvent,
20690        _window: &mut Window,
20691        cx: &mut Context<Self>,
20692    ) {
20693        if event.blurred != self.focus_handle {
20694            self.last_focused_descendant = Some(event.blurred);
20695        }
20696        self.selection_drag_state = SelectionDragState::None;
20697        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20698    }
20699
20700    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20701        self.blink_manager.update(cx, BlinkManager::disable);
20702        self.buffer
20703            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20704
20705        if let Some(blame) = self.blame.as_ref() {
20706            blame.update(cx, GitBlame::blur)
20707        }
20708        if !self.hover_state.focused(window, cx) {
20709            hide_hover(self, cx);
20710        }
20711        if !self
20712            .context_menu
20713            .borrow()
20714            .as_ref()
20715            .is_some_and(|context_menu| context_menu.focused(window, cx))
20716        {
20717            self.hide_context_menu(window, cx);
20718        }
20719        self.discard_inline_completion(false, cx);
20720        cx.emit(EditorEvent::Blurred);
20721        cx.notify();
20722    }
20723
20724    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20725        let mut pending: String = window
20726            .pending_input_keystrokes()
20727            .into_iter()
20728            .flatten()
20729            .filter_map(|keystroke| {
20730                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20731                    keystroke.key_char.clone()
20732                } else {
20733                    None
20734                }
20735            })
20736            .collect();
20737
20738        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20739            pending = "".to_string();
20740        }
20741
20742        let existing_pending = self
20743            .text_highlights::<PendingInput>(cx)
20744            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20745        if existing_pending.is_none() && pending.is_empty() {
20746            return;
20747        }
20748        let transaction =
20749            self.transact(window, cx, |this, window, cx| {
20750                let selections = this.selections.all::<usize>(cx);
20751                let edits = selections
20752                    .iter()
20753                    .map(|selection| (selection.end..selection.end, pending.clone()));
20754                this.edit(edits, cx);
20755                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20756                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20757                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20758                    }));
20759                });
20760                if let Some(existing_ranges) = existing_pending {
20761                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20762                    this.edit(edits, cx);
20763                }
20764            });
20765
20766        let snapshot = self.snapshot(window, cx);
20767        let ranges = self
20768            .selections
20769            .all::<usize>(cx)
20770            .into_iter()
20771            .map(|selection| {
20772                snapshot.buffer_snapshot.anchor_after(selection.end)
20773                    ..snapshot
20774                        .buffer_snapshot
20775                        .anchor_before(selection.end + pending.len())
20776            })
20777            .collect();
20778
20779        if pending.is_empty() {
20780            self.clear_highlights::<PendingInput>(cx);
20781        } else {
20782            self.highlight_text::<PendingInput>(
20783                ranges,
20784                HighlightStyle {
20785                    underline: Some(UnderlineStyle {
20786                        thickness: px(1.),
20787                        color: None,
20788                        wavy: false,
20789                    }),
20790                    ..Default::default()
20791                },
20792                cx,
20793            );
20794        }
20795
20796        self.ime_transaction = self.ime_transaction.or(transaction);
20797        if let Some(transaction) = self.ime_transaction {
20798            self.buffer.update(cx, |buffer, cx| {
20799                buffer.group_until_transaction(transaction, cx);
20800            });
20801        }
20802
20803        if self.text_highlights::<PendingInput>(cx).is_none() {
20804            self.ime_transaction.take();
20805        }
20806    }
20807
20808    pub fn register_action_renderer(
20809        &mut self,
20810        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20811    ) -> Subscription {
20812        let id = self.next_editor_action_id.post_inc();
20813        self.editor_actions
20814            .borrow_mut()
20815            .insert(id, Box::new(listener));
20816
20817        let editor_actions = self.editor_actions.clone();
20818        Subscription::new(move || {
20819            editor_actions.borrow_mut().remove(&id);
20820        })
20821    }
20822
20823    pub fn register_action<A: Action>(
20824        &mut self,
20825        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20826    ) -> Subscription {
20827        let id = self.next_editor_action_id.post_inc();
20828        let listener = Arc::new(listener);
20829        self.editor_actions.borrow_mut().insert(
20830            id,
20831            Box::new(move |_, window, _| {
20832                let listener = listener.clone();
20833                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20834                    let action = action.downcast_ref().unwrap();
20835                    if phase == DispatchPhase::Bubble {
20836                        listener(action, window, cx)
20837                    }
20838                })
20839            }),
20840        );
20841
20842        let editor_actions = self.editor_actions.clone();
20843        Subscription::new(move || {
20844            editor_actions.borrow_mut().remove(&id);
20845        })
20846    }
20847
20848    pub fn file_header_size(&self) -> u32 {
20849        FILE_HEADER_HEIGHT
20850    }
20851
20852    pub fn restore(
20853        &mut self,
20854        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20855        window: &mut Window,
20856        cx: &mut Context<Self>,
20857    ) {
20858        let workspace = self.workspace();
20859        let project = self.project.as_ref();
20860        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20861            let mut tasks = Vec::new();
20862            for (buffer_id, changes) in revert_changes {
20863                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20864                    buffer.update(cx, |buffer, cx| {
20865                        buffer.edit(
20866                            changes
20867                                .into_iter()
20868                                .map(|(range, text)| (range, text.to_string())),
20869                            None,
20870                            cx,
20871                        );
20872                    });
20873
20874                    if let Some(project) =
20875                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20876                    {
20877                        project.update(cx, |project, cx| {
20878                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20879                        })
20880                    }
20881                }
20882            }
20883            tasks
20884        });
20885        cx.spawn_in(window, async move |_, cx| {
20886            for (buffer, task) in save_tasks {
20887                let result = task.await;
20888                if result.is_err() {
20889                    let Some(path) = buffer
20890                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20891                        .ok()
20892                    else {
20893                        continue;
20894                    };
20895                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20896                        let Some(task) = cx
20897                            .update_window_entity(&workspace, |workspace, window, cx| {
20898                                workspace
20899                                    .open_path_preview(path, None, false, false, false, window, cx)
20900                            })
20901                            .ok()
20902                        else {
20903                            continue;
20904                        };
20905                        task.await.log_err();
20906                    }
20907                }
20908            }
20909        })
20910        .detach();
20911        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20912            selections.refresh()
20913        });
20914    }
20915
20916    pub fn to_pixel_point(
20917        &self,
20918        source: multi_buffer::Anchor,
20919        editor_snapshot: &EditorSnapshot,
20920        window: &mut Window,
20921    ) -> Option<gpui::Point<Pixels>> {
20922        let source_point = source.to_display_point(editor_snapshot);
20923        self.display_to_pixel_point(source_point, editor_snapshot, window)
20924    }
20925
20926    pub fn display_to_pixel_point(
20927        &self,
20928        source: DisplayPoint,
20929        editor_snapshot: &EditorSnapshot,
20930        window: &mut Window,
20931    ) -> Option<gpui::Point<Pixels>> {
20932        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20933        let text_layout_details = self.text_layout_details(window);
20934        let scroll_top = text_layout_details
20935            .scroll_anchor
20936            .scroll_position(editor_snapshot)
20937            .y;
20938
20939        if source.row().as_f32() < scroll_top.floor() {
20940            return None;
20941        }
20942        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20943        let source_y = line_height * (source.row().as_f32() - scroll_top);
20944        Some(gpui::Point::new(source_x, source_y))
20945    }
20946
20947    pub fn has_visible_completions_menu(&self) -> bool {
20948        !self.edit_prediction_preview_is_active()
20949            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20950                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20951            })
20952    }
20953
20954    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20955        if self.mode.is_minimap() {
20956            return;
20957        }
20958        self.addons
20959            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20960    }
20961
20962    pub fn unregister_addon<T: Addon>(&mut self) {
20963        self.addons.remove(&std::any::TypeId::of::<T>());
20964    }
20965
20966    pub fn addon<T: Addon>(&self) -> Option<&T> {
20967        let type_id = std::any::TypeId::of::<T>();
20968        self.addons
20969            .get(&type_id)
20970            .and_then(|item| item.to_any().downcast_ref::<T>())
20971    }
20972
20973    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20974        let type_id = std::any::TypeId::of::<T>();
20975        self.addons
20976            .get_mut(&type_id)
20977            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20978    }
20979
20980    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20981        let text_layout_details = self.text_layout_details(window);
20982        let style = &text_layout_details.editor_style;
20983        let font_id = window.text_system().resolve_font(&style.text.font());
20984        let font_size = style.text.font_size.to_pixels(window.rem_size());
20985        let line_height = style.text.line_height_in_pixels(window.rem_size());
20986        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20987        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20988
20989        CharacterDimensions {
20990            em_width,
20991            em_advance,
20992            line_height,
20993        }
20994    }
20995
20996    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20997        self.load_diff_task.clone()
20998    }
20999
21000    fn read_metadata_from_db(
21001        &mut self,
21002        item_id: u64,
21003        workspace_id: WorkspaceId,
21004        window: &mut Window,
21005        cx: &mut Context<Editor>,
21006    ) {
21007        if self.is_singleton(cx)
21008            && !self.mode.is_minimap()
21009            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21010        {
21011            let buffer_snapshot = OnceCell::new();
21012
21013            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21014                if !folds.is_empty() {
21015                    let snapshot =
21016                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21017                    self.fold_ranges(
21018                        folds
21019                            .into_iter()
21020                            .map(|(start, end)| {
21021                                snapshot.clip_offset(start, Bias::Left)
21022                                    ..snapshot.clip_offset(end, Bias::Right)
21023                            })
21024                            .collect(),
21025                        false,
21026                        window,
21027                        cx,
21028                    );
21029                }
21030            }
21031
21032            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21033                if !selections.is_empty() {
21034                    let snapshot =
21035                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21036                    // skip adding the initial selection to selection history
21037                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21038                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21039                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21040                            snapshot.clip_offset(start, Bias::Left)
21041                                ..snapshot.clip_offset(end, Bias::Right)
21042                        }));
21043                    });
21044                    self.selection_history.mode = SelectionHistoryMode::Normal;
21045                }
21046            };
21047        }
21048
21049        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21050    }
21051
21052    fn update_lsp_data(
21053        &mut self,
21054        ignore_cache: bool,
21055        for_buffer: Option<BufferId>,
21056        window: &mut Window,
21057        cx: &mut Context<'_, Self>,
21058    ) {
21059        self.pull_diagnostics(for_buffer, window, cx);
21060        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21061    }
21062}
21063
21064fn vim_enabled(cx: &App) -> bool {
21065    cx.global::<SettingsStore>()
21066        .raw_user_settings()
21067        .get("vim_mode")
21068        == Some(&serde_json::Value::Bool(true))
21069}
21070
21071fn process_completion_for_edit(
21072    completion: &Completion,
21073    intent: CompletionIntent,
21074    buffer: &Entity<Buffer>,
21075    cursor_position: &text::Anchor,
21076    cx: &mut Context<Editor>,
21077) -> CompletionEdit {
21078    let buffer = buffer.read(cx);
21079    let buffer_snapshot = buffer.snapshot();
21080    let (snippet, new_text) = if completion.is_snippet() {
21081        // Workaround for typescript language server issues so that methods don't expand within
21082        // strings and functions with type expressions. The previous point is used because the query
21083        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21084        let mut snippet_source = completion.new_text.clone();
21085        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21086        previous_point.column = previous_point.column.saturating_sub(1);
21087        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21088            if scope.prefers_label_for_snippet_in_completion() {
21089                if let Some(label) = completion.label() {
21090                    if matches!(
21091                        completion.kind(),
21092                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21093                    ) {
21094                        snippet_source = label;
21095                    }
21096                }
21097            }
21098        }
21099        match Snippet::parse(&snippet_source).log_err() {
21100            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21101            None => (None, completion.new_text.clone()),
21102        }
21103    } else {
21104        (None, completion.new_text.clone())
21105    };
21106
21107    let mut range_to_replace = {
21108        let replace_range = &completion.replace_range;
21109        if let CompletionSource::Lsp {
21110            insert_range: Some(insert_range),
21111            ..
21112        } = &completion.source
21113        {
21114            debug_assert_eq!(
21115                insert_range.start, replace_range.start,
21116                "insert_range and replace_range should start at the same position"
21117            );
21118            debug_assert!(
21119                insert_range
21120                    .start
21121                    .cmp(&cursor_position, &buffer_snapshot)
21122                    .is_le(),
21123                "insert_range should start before or at cursor position"
21124            );
21125            debug_assert!(
21126                replace_range
21127                    .start
21128                    .cmp(&cursor_position, &buffer_snapshot)
21129                    .is_le(),
21130                "replace_range should start before or at cursor position"
21131            );
21132            debug_assert!(
21133                insert_range
21134                    .end
21135                    .cmp(&cursor_position, &buffer_snapshot)
21136                    .is_le(),
21137                "insert_range should end before or at cursor position"
21138            );
21139
21140            let should_replace = match intent {
21141                CompletionIntent::CompleteWithInsert => false,
21142                CompletionIntent::CompleteWithReplace => true,
21143                CompletionIntent::Complete | CompletionIntent::Compose => {
21144                    let insert_mode =
21145                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21146                            .completions
21147                            .lsp_insert_mode;
21148                    match insert_mode {
21149                        LspInsertMode::Insert => false,
21150                        LspInsertMode::Replace => true,
21151                        LspInsertMode::ReplaceSubsequence => {
21152                            let mut text_to_replace = buffer.chars_for_range(
21153                                buffer.anchor_before(replace_range.start)
21154                                    ..buffer.anchor_after(replace_range.end),
21155                            );
21156                            let mut current_needle = text_to_replace.next();
21157                            for haystack_ch in completion.label.text.chars() {
21158                                if let Some(needle_ch) = current_needle {
21159                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21160                                        current_needle = text_to_replace.next();
21161                                    }
21162                                }
21163                            }
21164                            current_needle.is_none()
21165                        }
21166                        LspInsertMode::ReplaceSuffix => {
21167                            if replace_range
21168                                .end
21169                                .cmp(&cursor_position, &buffer_snapshot)
21170                                .is_gt()
21171                            {
21172                                let range_after_cursor = *cursor_position..replace_range.end;
21173                                let text_after_cursor = buffer
21174                                    .text_for_range(
21175                                        buffer.anchor_before(range_after_cursor.start)
21176                                            ..buffer.anchor_after(range_after_cursor.end),
21177                                    )
21178                                    .collect::<String>()
21179                                    .to_ascii_lowercase();
21180                                completion
21181                                    .label
21182                                    .text
21183                                    .to_ascii_lowercase()
21184                                    .ends_with(&text_after_cursor)
21185                            } else {
21186                                true
21187                            }
21188                        }
21189                    }
21190                }
21191            };
21192
21193            if should_replace {
21194                replace_range.clone()
21195            } else {
21196                insert_range.clone()
21197            }
21198        } else {
21199            replace_range.clone()
21200        }
21201    };
21202
21203    if range_to_replace
21204        .end
21205        .cmp(&cursor_position, &buffer_snapshot)
21206        .is_lt()
21207    {
21208        range_to_replace.end = *cursor_position;
21209    }
21210
21211    CompletionEdit {
21212        new_text,
21213        replace_range: range_to_replace.to_offset(&buffer),
21214        snippet,
21215    }
21216}
21217
21218struct CompletionEdit {
21219    new_text: String,
21220    replace_range: Range<usize>,
21221    snippet: Option<Snippet>,
21222}
21223
21224fn insert_extra_newline_brackets(
21225    buffer: &MultiBufferSnapshot,
21226    range: Range<usize>,
21227    language: &language::LanguageScope,
21228) -> bool {
21229    let leading_whitespace_len = buffer
21230        .reversed_chars_at(range.start)
21231        .take_while(|c| c.is_whitespace() && *c != '\n')
21232        .map(|c| c.len_utf8())
21233        .sum::<usize>();
21234    let trailing_whitespace_len = buffer
21235        .chars_at(range.end)
21236        .take_while(|c| c.is_whitespace() && *c != '\n')
21237        .map(|c| c.len_utf8())
21238        .sum::<usize>();
21239    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21240
21241    language.brackets().any(|(pair, enabled)| {
21242        let pair_start = pair.start.trim_end();
21243        let pair_end = pair.end.trim_start();
21244
21245        enabled
21246            && pair.newline
21247            && buffer.contains_str_at(range.end, pair_end)
21248            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21249    })
21250}
21251
21252fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21253    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21254        [(buffer, range, _)] => (*buffer, range.clone()),
21255        _ => return false,
21256    };
21257    let pair = {
21258        let mut result: Option<BracketMatch> = None;
21259
21260        for pair in buffer
21261            .all_bracket_ranges(range.clone())
21262            .filter(move |pair| {
21263                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21264            })
21265        {
21266            let len = pair.close_range.end - pair.open_range.start;
21267
21268            if let Some(existing) = &result {
21269                let existing_len = existing.close_range.end - existing.open_range.start;
21270                if len > existing_len {
21271                    continue;
21272                }
21273            }
21274
21275            result = Some(pair);
21276        }
21277
21278        result
21279    };
21280    let Some(pair) = pair else {
21281        return false;
21282    };
21283    pair.newline_only
21284        && buffer
21285            .chars_for_range(pair.open_range.end..range.start)
21286            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21287            .all(|c| c.is_whitespace() && c != '\n')
21288}
21289
21290fn update_uncommitted_diff_for_buffer(
21291    editor: Entity<Editor>,
21292    project: &Entity<Project>,
21293    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21294    buffer: Entity<MultiBuffer>,
21295    cx: &mut App,
21296) -> Task<()> {
21297    let mut tasks = Vec::new();
21298    project.update(cx, |project, cx| {
21299        for buffer in buffers {
21300            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21301                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21302            }
21303        }
21304    });
21305    cx.spawn(async move |cx| {
21306        let diffs = future::join_all(tasks).await;
21307        if editor
21308            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21309            .unwrap_or(false)
21310        {
21311            return;
21312        }
21313
21314        buffer
21315            .update(cx, |buffer, cx| {
21316                for diff in diffs.into_iter().flatten() {
21317                    buffer.add_diff(diff, cx);
21318                }
21319            })
21320            .ok();
21321    })
21322}
21323
21324fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21325    let tab_size = tab_size.get() as usize;
21326    let mut width = offset;
21327
21328    for ch in text.chars() {
21329        width += if ch == '\t' {
21330            tab_size - (width % tab_size)
21331        } else {
21332            1
21333        };
21334    }
21335
21336    width - offset
21337}
21338
21339#[cfg(test)]
21340mod tests {
21341    use super::*;
21342
21343    #[test]
21344    fn test_string_size_with_expanded_tabs() {
21345        let nz = |val| NonZeroU32::new(val).unwrap();
21346        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21347        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21348        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21349        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21350        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21351        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21352        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21353        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21354    }
21355}
21356
21357/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21358struct WordBreakingTokenizer<'a> {
21359    input: &'a str,
21360}
21361
21362impl<'a> WordBreakingTokenizer<'a> {
21363    fn new(input: &'a str) -> Self {
21364        Self { input }
21365    }
21366}
21367
21368fn is_char_ideographic(ch: char) -> bool {
21369    use unicode_script::Script::*;
21370    use unicode_script::UnicodeScript;
21371    matches!(ch.script(), Han | Tangut | Yi)
21372}
21373
21374fn is_grapheme_ideographic(text: &str) -> bool {
21375    text.chars().any(is_char_ideographic)
21376}
21377
21378fn is_grapheme_whitespace(text: &str) -> bool {
21379    text.chars().any(|x| x.is_whitespace())
21380}
21381
21382fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21383    text.chars().next().map_or(false, |ch| {
21384        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21385    })
21386}
21387
21388#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21389enum WordBreakToken<'a> {
21390    Word { token: &'a str, grapheme_len: usize },
21391    InlineWhitespace { token: &'a str, grapheme_len: usize },
21392    Newline,
21393}
21394
21395impl<'a> Iterator for WordBreakingTokenizer<'a> {
21396    /// Yields a span, the count of graphemes in the token, and whether it was
21397    /// whitespace. Note that it also breaks at word boundaries.
21398    type Item = WordBreakToken<'a>;
21399
21400    fn next(&mut self) -> Option<Self::Item> {
21401        use unicode_segmentation::UnicodeSegmentation;
21402        if self.input.is_empty() {
21403            return None;
21404        }
21405
21406        let mut iter = self.input.graphemes(true).peekable();
21407        let mut offset = 0;
21408        let mut grapheme_len = 0;
21409        if let Some(first_grapheme) = iter.next() {
21410            let is_newline = first_grapheme == "\n";
21411            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21412            offset += first_grapheme.len();
21413            grapheme_len += 1;
21414            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21415                if let Some(grapheme) = iter.peek().copied() {
21416                    if should_stay_with_preceding_ideograph(grapheme) {
21417                        offset += grapheme.len();
21418                        grapheme_len += 1;
21419                    }
21420                }
21421            } else {
21422                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21423                let mut next_word_bound = words.peek().copied();
21424                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21425                    next_word_bound = words.next();
21426                }
21427                while let Some(grapheme) = iter.peek().copied() {
21428                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21429                        break;
21430                    };
21431                    if is_grapheme_whitespace(grapheme) != is_whitespace
21432                        || (grapheme == "\n") != is_newline
21433                    {
21434                        break;
21435                    };
21436                    offset += grapheme.len();
21437                    grapheme_len += 1;
21438                    iter.next();
21439                }
21440            }
21441            let token = &self.input[..offset];
21442            self.input = &self.input[offset..];
21443            if token == "\n" {
21444                Some(WordBreakToken::Newline)
21445            } else if is_whitespace {
21446                Some(WordBreakToken::InlineWhitespace {
21447                    token,
21448                    grapheme_len,
21449                })
21450            } else {
21451                Some(WordBreakToken::Word {
21452                    token,
21453                    grapheme_len,
21454                })
21455            }
21456        } else {
21457            None
21458        }
21459    }
21460}
21461
21462#[test]
21463fn test_word_breaking_tokenizer() {
21464    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21465        ("", &[]),
21466        ("  ", &[whitespace("  ", 2)]),
21467        ("Ʒ", &[word("Ʒ", 1)]),
21468        ("Ǽ", &[word("Ǽ", 1)]),
21469        ("", &[word("", 1)]),
21470        ("⋑⋑", &[word("⋑⋑", 2)]),
21471        (
21472            "原理,进而",
21473            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21474        ),
21475        (
21476            "hello world",
21477            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21478        ),
21479        (
21480            "hello, world",
21481            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21482        ),
21483        (
21484            "  hello world",
21485            &[
21486                whitespace("  ", 2),
21487                word("hello", 5),
21488                whitespace(" ", 1),
21489                word("world", 5),
21490            ],
21491        ),
21492        (
21493            "这是什么 \n 钢笔",
21494            &[
21495                word("", 1),
21496                word("", 1),
21497                word("", 1),
21498                word("", 1),
21499                whitespace(" ", 1),
21500                newline(),
21501                whitespace(" ", 1),
21502                word("", 1),
21503                word("", 1),
21504            ],
21505        ),
21506        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21507    ];
21508
21509    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21510        WordBreakToken::Word {
21511            token,
21512            grapheme_len,
21513        }
21514    }
21515
21516    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21517        WordBreakToken::InlineWhitespace {
21518            token,
21519            grapheme_len,
21520        }
21521    }
21522
21523    fn newline() -> WordBreakToken<'static> {
21524        WordBreakToken::Newline
21525    }
21526
21527    for (input, result) in tests {
21528        assert_eq!(
21529            WordBreakingTokenizer::new(input)
21530                .collect::<Vec<_>>()
21531                .as_slice(),
21532            *result,
21533        );
21534    }
21535}
21536
21537fn wrap_with_prefix(
21538    first_line_prefix: String,
21539    subsequent_lines_prefix: String,
21540    unwrapped_text: String,
21541    wrap_column: usize,
21542    tab_size: NonZeroU32,
21543    preserve_existing_whitespace: bool,
21544) -> String {
21545    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21546    let subsequent_lines_prefix_len =
21547        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21548    let mut wrapped_text = String::new();
21549    let mut current_line = first_line_prefix.clone();
21550    let mut is_first_line = true;
21551
21552    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21553    let mut current_line_len = first_line_prefix_len;
21554    let mut in_whitespace = false;
21555    for token in tokenizer {
21556        let have_preceding_whitespace = in_whitespace;
21557        match token {
21558            WordBreakToken::Word {
21559                token,
21560                grapheme_len,
21561            } => {
21562                in_whitespace = false;
21563                let current_prefix_len = if is_first_line {
21564                    first_line_prefix_len
21565                } else {
21566                    subsequent_lines_prefix_len
21567                };
21568                if current_line_len + grapheme_len > wrap_column
21569                    && current_line_len != current_prefix_len
21570                {
21571                    wrapped_text.push_str(current_line.trim_end());
21572                    wrapped_text.push('\n');
21573                    is_first_line = false;
21574                    current_line = subsequent_lines_prefix.clone();
21575                    current_line_len = subsequent_lines_prefix_len;
21576                }
21577                current_line.push_str(token);
21578                current_line_len += grapheme_len;
21579            }
21580            WordBreakToken::InlineWhitespace {
21581                mut token,
21582                mut grapheme_len,
21583            } => {
21584                in_whitespace = true;
21585                if have_preceding_whitespace && !preserve_existing_whitespace {
21586                    continue;
21587                }
21588                if !preserve_existing_whitespace {
21589                    token = " ";
21590                    grapheme_len = 1;
21591                }
21592                let current_prefix_len = if is_first_line {
21593                    first_line_prefix_len
21594                } else {
21595                    subsequent_lines_prefix_len
21596                };
21597                if current_line_len + grapheme_len > wrap_column {
21598                    wrapped_text.push_str(current_line.trim_end());
21599                    wrapped_text.push('\n');
21600                    is_first_line = false;
21601                    current_line = subsequent_lines_prefix.clone();
21602                    current_line_len = subsequent_lines_prefix_len;
21603                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21604                    current_line.push_str(token);
21605                    current_line_len += grapheme_len;
21606                }
21607            }
21608            WordBreakToken::Newline => {
21609                in_whitespace = true;
21610                let current_prefix_len = if is_first_line {
21611                    first_line_prefix_len
21612                } else {
21613                    subsequent_lines_prefix_len
21614                };
21615                if preserve_existing_whitespace {
21616                    wrapped_text.push_str(current_line.trim_end());
21617                    wrapped_text.push('\n');
21618                    is_first_line = false;
21619                    current_line = subsequent_lines_prefix.clone();
21620                    current_line_len = subsequent_lines_prefix_len;
21621                } else if have_preceding_whitespace {
21622                    continue;
21623                } else if current_line_len + 1 > wrap_column
21624                    && current_line_len != current_prefix_len
21625                {
21626                    wrapped_text.push_str(current_line.trim_end());
21627                    wrapped_text.push('\n');
21628                    is_first_line = false;
21629                    current_line = subsequent_lines_prefix.clone();
21630                    current_line_len = subsequent_lines_prefix_len;
21631                } else if current_line_len != current_prefix_len {
21632                    current_line.push(' ');
21633                    current_line_len += 1;
21634                }
21635            }
21636        }
21637    }
21638
21639    if !current_line.is_empty() {
21640        wrapped_text.push_str(&current_line);
21641    }
21642    wrapped_text
21643}
21644
21645#[test]
21646fn test_wrap_with_prefix() {
21647    assert_eq!(
21648        wrap_with_prefix(
21649            "# ".to_string(),
21650            "# ".to_string(),
21651            "abcdefg".to_string(),
21652            4,
21653            NonZeroU32::new(4).unwrap(),
21654            false,
21655        ),
21656        "# abcdefg"
21657    );
21658    assert_eq!(
21659        wrap_with_prefix(
21660            "".to_string(),
21661            "".to_string(),
21662            "\thello world".to_string(),
21663            8,
21664            NonZeroU32::new(4).unwrap(),
21665            false,
21666        ),
21667        "hello\nworld"
21668    );
21669    assert_eq!(
21670        wrap_with_prefix(
21671            "// ".to_string(),
21672            "// ".to_string(),
21673            "xx \nyy zz aa bb cc".to_string(),
21674            12,
21675            NonZeroU32::new(4).unwrap(),
21676            false,
21677        ),
21678        "// xx yy zz\n// aa bb cc"
21679    );
21680    assert_eq!(
21681        wrap_with_prefix(
21682            String::new(),
21683            String::new(),
21684            "这是什么 \n 钢笔".to_string(),
21685            3,
21686            NonZeroU32::new(4).unwrap(),
21687            false,
21688        ),
21689        "这是什\n么 钢\n"
21690    );
21691}
21692
21693pub trait CollaborationHub {
21694    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21695    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21696    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21697}
21698
21699impl CollaborationHub for Entity<Project> {
21700    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21701        self.read(cx).collaborators()
21702    }
21703
21704    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21705        self.read(cx).user_store().read(cx).participant_indices()
21706    }
21707
21708    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21709        let this = self.read(cx);
21710        let user_ids = this.collaborators().values().map(|c| c.user_id);
21711        this.user_store().read(cx).participant_names(user_ids, cx)
21712    }
21713}
21714
21715pub trait SemanticsProvider {
21716    fn hover(
21717        &self,
21718        buffer: &Entity<Buffer>,
21719        position: text::Anchor,
21720        cx: &mut App,
21721    ) -> Option<Task<Vec<project::Hover>>>;
21722
21723    fn inline_values(
21724        &self,
21725        buffer_handle: Entity<Buffer>,
21726        range: Range<text::Anchor>,
21727        cx: &mut App,
21728    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21729
21730    fn inlay_hints(
21731        &self,
21732        buffer_handle: Entity<Buffer>,
21733        range: Range<text::Anchor>,
21734        cx: &mut App,
21735    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21736
21737    fn resolve_inlay_hint(
21738        &self,
21739        hint: InlayHint,
21740        buffer_handle: Entity<Buffer>,
21741        server_id: LanguageServerId,
21742        cx: &mut App,
21743    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21744
21745    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21746
21747    fn document_highlights(
21748        &self,
21749        buffer: &Entity<Buffer>,
21750        position: text::Anchor,
21751        cx: &mut App,
21752    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21753
21754    fn definitions(
21755        &self,
21756        buffer: &Entity<Buffer>,
21757        position: text::Anchor,
21758        kind: GotoDefinitionKind,
21759        cx: &mut App,
21760    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21761
21762    fn range_for_rename(
21763        &self,
21764        buffer: &Entity<Buffer>,
21765        position: text::Anchor,
21766        cx: &mut App,
21767    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21768
21769    fn perform_rename(
21770        &self,
21771        buffer: &Entity<Buffer>,
21772        position: text::Anchor,
21773        new_name: String,
21774        cx: &mut App,
21775    ) -> Option<Task<Result<ProjectTransaction>>>;
21776}
21777
21778pub trait CompletionProvider {
21779    fn completions(
21780        &self,
21781        excerpt_id: ExcerptId,
21782        buffer: &Entity<Buffer>,
21783        buffer_position: text::Anchor,
21784        trigger: CompletionContext,
21785        window: &mut Window,
21786        cx: &mut Context<Editor>,
21787    ) -> Task<Result<Vec<CompletionResponse>>>;
21788
21789    fn resolve_completions(
21790        &self,
21791        _buffer: Entity<Buffer>,
21792        _completion_indices: Vec<usize>,
21793        _completions: Rc<RefCell<Box<[Completion]>>>,
21794        _cx: &mut Context<Editor>,
21795    ) -> Task<Result<bool>> {
21796        Task::ready(Ok(false))
21797    }
21798
21799    fn apply_additional_edits_for_completion(
21800        &self,
21801        _buffer: Entity<Buffer>,
21802        _completions: Rc<RefCell<Box<[Completion]>>>,
21803        _completion_index: usize,
21804        _push_to_history: bool,
21805        _cx: &mut Context<Editor>,
21806    ) -> Task<Result<Option<language::Transaction>>> {
21807        Task::ready(Ok(None))
21808    }
21809
21810    fn is_completion_trigger(
21811        &self,
21812        buffer: &Entity<Buffer>,
21813        position: language::Anchor,
21814        text: &str,
21815        trigger_in_words: bool,
21816        menu_is_open: bool,
21817        cx: &mut Context<Editor>,
21818    ) -> bool;
21819
21820    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21821
21822    fn sort_completions(&self) -> bool {
21823        true
21824    }
21825
21826    fn filter_completions(&self) -> bool {
21827        true
21828    }
21829}
21830
21831pub trait CodeActionProvider {
21832    fn id(&self) -> Arc<str>;
21833
21834    fn code_actions(
21835        &self,
21836        buffer: &Entity<Buffer>,
21837        range: Range<text::Anchor>,
21838        window: &mut Window,
21839        cx: &mut App,
21840    ) -> Task<Result<Vec<CodeAction>>>;
21841
21842    fn apply_code_action(
21843        &self,
21844        buffer_handle: Entity<Buffer>,
21845        action: CodeAction,
21846        excerpt_id: ExcerptId,
21847        push_to_history: bool,
21848        window: &mut Window,
21849        cx: &mut App,
21850    ) -> Task<Result<ProjectTransaction>>;
21851}
21852
21853impl CodeActionProvider for Entity<Project> {
21854    fn id(&self) -> Arc<str> {
21855        "project".into()
21856    }
21857
21858    fn code_actions(
21859        &self,
21860        buffer: &Entity<Buffer>,
21861        range: Range<text::Anchor>,
21862        _window: &mut Window,
21863        cx: &mut App,
21864    ) -> Task<Result<Vec<CodeAction>>> {
21865        self.update(cx, |project, cx| {
21866            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21867            let code_actions = project.code_actions(buffer, range, None, cx);
21868            cx.background_spawn(async move {
21869                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21870                Ok(code_lens_actions
21871                    .context("code lens fetch")?
21872                    .into_iter()
21873                    .chain(code_actions.context("code action fetch")?)
21874                    .collect())
21875            })
21876        })
21877    }
21878
21879    fn apply_code_action(
21880        &self,
21881        buffer_handle: Entity<Buffer>,
21882        action: CodeAction,
21883        _excerpt_id: ExcerptId,
21884        push_to_history: bool,
21885        _window: &mut Window,
21886        cx: &mut App,
21887    ) -> Task<Result<ProjectTransaction>> {
21888        self.update(cx, |project, cx| {
21889            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21890        })
21891    }
21892}
21893
21894fn snippet_completions(
21895    project: &Project,
21896    buffer: &Entity<Buffer>,
21897    buffer_position: text::Anchor,
21898    cx: &mut App,
21899) -> Task<Result<CompletionResponse>> {
21900    let languages = buffer.read(cx).languages_at(buffer_position);
21901    let snippet_store = project.snippets().read(cx);
21902
21903    let scopes: Vec<_> = languages
21904        .iter()
21905        .filter_map(|language| {
21906            let language_name = language.lsp_id();
21907            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21908
21909            if snippets.is_empty() {
21910                None
21911            } else {
21912                Some((language.default_scope(), snippets))
21913            }
21914        })
21915        .collect();
21916
21917    if scopes.is_empty() {
21918        return Task::ready(Ok(CompletionResponse {
21919            completions: vec![],
21920            is_incomplete: false,
21921        }));
21922    }
21923
21924    let snapshot = buffer.read(cx).text_snapshot();
21925    let chars: String = snapshot
21926        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21927        .collect();
21928    let executor = cx.background_executor().clone();
21929
21930    cx.background_spawn(async move {
21931        let mut is_incomplete = false;
21932        let mut completions: Vec<Completion> = Vec::new();
21933        for (scope, snippets) in scopes.into_iter() {
21934            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21935            let mut last_word = chars
21936                .chars()
21937                .take_while(|c| classifier.is_word(*c))
21938                .collect::<String>();
21939            last_word = last_word.chars().rev().collect();
21940
21941            if last_word.is_empty() {
21942                return Ok(CompletionResponse {
21943                    completions: vec![],
21944                    is_incomplete: true,
21945                });
21946            }
21947
21948            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21949            let to_lsp = |point: &text::Anchor| {
21950                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21951                point_to_lsp(end)
21952            };
21953            let lsp_end = to_lsp(&buffer_position);
21954
21955            let candidates = snippets
21956                .iter()
21957                .enumerate()
21958                .flat_map(|(ix, snippet)| {
21959                    snippet
21960                        .prefix
21961                        .iter()
21962                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21963                })
21964                .collect::<Vec<StringMatchCandidate>>();
21965
21966            const MAX_RESULTS: usize = 100;
21967            let mut matches = fuzzy::match_strings(
21968                &candidates,
21969                &last_word,
21970                last_word.chars().any(|c| c.is_uppercase()),
21971                true,
21972                MAX_RESULTS,
21973                &Default::default(),
21974                executor.clone(),
21975            )
21976            .await;
21977
21978            if matches.len() >= MAX_RESULTS {
21979                is_incomplete = true;
21980            }
21981
21982            // Remove all candidates where the query's start does not match the start of any word in the candidate
21983            if let Some(query_start) = last_word.chars().next() {
21984                matches.retain(|string_match| {
21985                    split_words(&string_match.string).any(|word| {
21986                        // Check that the first codepoint of the word as lowercase matches the first
21987                        // codepoint of the query as lowercase
21988                        word.chars()
21989                            .flat_map(|codepoint| codepoint.to_lowercase())
21990                            .zip(query_start.to_lowercase())
21991                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21992                    })
21993                });
21994            }
21995
21996            let matched_strings = matches
21997                .into_iter()
21998                .map(|m| m.string)
21999                .collect::<HashSet<_>>();
22000
22001            completions.extend(snippets.iter().filter_map(|snippet| {
22002                let matching_prefix = snippet
22003                    .prefix
22004                    .iter()
22005                    .find(|prefix| matched_strings.contains(*prefix))?;
22006                let start = as_offset - last_word.len();
22007                let start = snapshot.anchor_before(start);
22008                let range = start..buffer_position;
22009                let lsp_start = to_lsp(&start);
22010                let lsp_range = lsp::Range {
22011                    start: lsp_start,
22012                    end: lsp_end,
22013                };
22014                Some(Completion {
22015                    replace_range: range,
22016                    new_text: snippet.body.clone(),
22017                    source: CompletionSource::Lsp {
22018                        insert_range: None,
22019                        server_id: LanguageServerId(usize::MAX),
22020                        resolved: true,
22021                        lsp_completion: Box::new(lsp::CompletionItem {
22022                            label: snippet.prefix.first().unwrap().clone(),
22023                            kind: Some(CompletionItemKind::SNIPPET),
22024                            label_details: snippet.description.as_ref().map(|description| {
22025                                lsp::CompletionItemLabelDetails {
22026                                    detail: Some(description.clone()),
22027                                    description: None,
22028                                }
22029                            }),
22030                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22031                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22032                                lsp::InsertReplaceEdit {
22033                                    new_text: snippet.body.clone(),
22034                                    insert: lsp_range,
22035                                    replace: lsp_range,
22036                                },
22037                            )),
22038                            filter_text: Some(snippet.body.clone()),
22039                            sort_text: Some(char::MAX.to_string()),
22040                            ..lsp::CompletionItem::default()
22041                        }),
22042                        lsp_defaults: None,
22043                    },
22044                    label: CodeLabel {
22045                        text: matching_prefix.clone(),
22046                        runs: Vec::new(),
22047                        filter_range: 0..matching_prefix.len(),
22048                    },
22049                    icon_path: None,
22050                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22051                        single_line: snippet.name.clone().into(),
22052                        plain_text: snippet
22053                            .description
22054                            .clone()
22055                            .map(|description| description.into()),
22056                    }),
22057                    insert_text_mode: None,
22058                    confirm: None,
22059                })
22060            }))
22061        }
22062
22063        Ok(CompletionResponse {
22064            completions,
22065            is_incomplete,
22066        })
22067    })
22068}
22069
22070impl CompletionProvider for Entity<Project> {
22071    fn completions(
22072        &self,
22073        _excerpt_id: ExcerptId,
22074        buffer: &Entity<Buffer>,
22075        buffer_position: text::Anchor,
22076        options: CompletionContext,
22077        _window: &mut Window,
22078        cx: &mut Context<Editor>,
22079    ) -> Task<Result<Vec<CompletionResponse>>> {
22080        self.update(cx, |project, cx| {
22081            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22082            let project_completions = project.completions(buffer, buffer_position, options, cx);
22083            cx.background_spawn(async move {
22084                let mut responses = project_completions.await?;
22085                let snippets = snippets.await?;
22086                if !snippets.completions.is_empty() {
22087                    responses.push(snippets);
22088                }
22089                Ok(responses)
22090            })
22091        })
22092    }
22093
22094    fn resolve_completions(
22095        &self,
22096        buffer: Entity<Buffer>,
22097        completion_indices: Vec<usize>,
22098        completions: Rc<RefCell<Box<[Completion]>>>,
22099        cx: &mut Context<Editor>,
22100    ) -> Task<Result<bool>> {
22101        self.update(cx, |project, cx| {
22102            project.lsp_store().update(cx, |lsp_store, cx| {
22103                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22104            })
22105        })
22106    }
22107
22108    fn apply_additional_edits_for_completion(
22109        &self,
22110        buffer: Entity<Buffer>,
22111        completions: Rc<RefCell<Box<[Completion]>>>,
22112        completion_index: usize,
22113        push_to_history: bool,
22114        cx: &mut Context<Editor>,
22115    ) -> Task<Result<Option<language::Transaction>>> {
22116        self.update(cx, |project, cx| {
22117            project.lsp_store().update(cx, |lsp_store, cx| {
22118                lsp_store.apply_additional_edits_for_completion(
22119                    buffer,
22120                    completions,
22121                    completion_index,
22122                    push_to_history,
22123                    cx,
22124                )
22125            })
22126        })
22127    }
22128
22129    fn is_completion_trigger(
22130        &self,
22131        buffer: &Entity<Buffer>,
22132        position: language::Anchor,
22133        text: &str,
22134        trigger_in_words: bool,
22135        menu_is_open: bool,
22136        cx: &mut Context<Editor>,
22137    ) -> bool {
22138        let mut chars = text.chars();
22139        let char = if let Some(char) = chars.next() {
22140            char
22141        } else {
22142            return false;
22143        };
22144        if chars.next().is_some() {
22145            return false;
22146        }
22147
22148        let buffer = buffer.read(cx);
22149        let snapshot = buffer.snapshot();
22150        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22151            return false;
22152        }
22153        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22154        if trigger_in_words && classifier.is_word(char) {
22155            return true;
22156        }
22157
22158        buffer.completion_triggers().contains(text)
22159    }
22160}
22161
22162impl SemanticsProvider for Entity<Project> {
22163    fn hover(
22164        &self,
22165        buffer: &Entity<Buffer>,
22166        position: text::Anchor,
22167        cx: &mut App,
22168    ) -> Option<Task<Vec<project::Hover>>> {
22169        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22170    }
22171
22172    fn document_highlights(
22173        &self,
22174        buffer: &Entity<Buffer>,
22175        position: text::Anchor,
22176        cx: &mut App,
22177    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22178        Some(self.update(cx, |project, cx| {
22179            project.document_highlights(buffer, position, cx)
22180        }))
22181    }
22182
22183    fn definitions(
22184        &self,
22185        buffer: &Entity<Buffer>,
22186        position: text::Anchor,
22187        kind: GotoDefinitionKind,
22188        cx: &mut App,
22189    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22190        Some(self.update(cx, |project, cx| match kind {
22191            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22192            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22193            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22194            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22195        }))
22196    }
22197
22198    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22199        // TODO: make this work for remote projects
22200        self.update(cx, |project, cx| {
22201            if project
22202                .active_debug_session(cx)
22203                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22204            {
22205                return true;
22206            }
22207
22208            buffer.update(cx, |buffer, cx| {
22209                project.any_language_server_supports_inlay_hints(buffer, cx)
22210            })
22211        })
22212    }
22213
22214    fn inline_values(
22215        &self,
22216        buffer_handle: Entity<Buffer>,
22217        range: Range<text::Anchor>,
22218        cx: &mut App,
22219    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22220        self.update(cx, |project, cx| {
22221            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22222
22223            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22224        })
22225    }
22226
22227    fn inlay_hints(
22228        &self,
22229        buffer_handle: Entity<Buffer>,
22230        range: Range<text::Anchor>,
22231        cx: &mut App,
22232    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22233        Some(self.update(cx, |project, cx| {
22234            project.inlay_hints(buffer_handle, range, cx)
22235        }))
22236    }
22237
22238    fn resolve_inlay_hint(
22239        &self,
22240        hint: InlayHint,
22241        buffer_handle: Entity<Buffer>,
22242        server_id: LanguageServerId,
22243        cx: &mut App,
22244    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22245        Some(self.update(cx, |project, cx| {
22246            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22247        }))
22248    }
22249
22250    fn range_for_rename(
22251        &self,
22252        buffer: &Entity<Buffer>,
22253        position: text::Anchor,
22254        cx: &mut App,
22255    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22256        Some(self.update(cx, |project, cx| {
22257            let buffer = buffer.clone();
22258            let task = project.prepare_rename(buffer.clone(), position, cx);
22259            cx.spawn(async move |_, cx| {
22260                Ok(match task.await? {
22261                    PrepareRenameResponse::Success(range) => Some(range),
22262                    PrepareRenameResponse::InvalidPosition => None,
22263                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22264                        // Fallback on using TreeSitter info to determine identifier range
22265                        buffer.read_with(cx, |buffer, _| {
22266                            let snapshot = buffer.snapshot();
22267                            let (range, kind) = snapshot.surrounding_word(position, false);
22268                            if kind != Some(CharKind::Word) {
22269                                return None;
22270                            }
22271                            Some(
22272                                snapshot.anchor_before(range.start)
22273                                    ..snapshot.anchor_after(range.end),
22274                            )
22275                        })?
22276                    }
22277                })
22278            })
22279        }))
22280    }
22281
22282    fn perform_rename(
22283        &self,
22284        buffer: &Entity<Buffer>,
22285        position: text::Anchor,
22286        new_name: String,
22287        cx: &mut App,
22288    ) -> Option<Task<Result<ProjectTransaction>>> {
22289        Some(self.update(cx, |project, cx| {
22290            project.perform_rename(buffer.clone(), position, new_name, cx)
22291        }))
22292    }
22293}
22294
22295fn inlay_hint_settings(
22296    location: Anchor,
22297    snapshot: &MultiBufferSnapshot,
22298    cx: &mut Context<Editor>,
22299) -> InlayHintSettings {
22300    let file = snapshot.file_at(location);
22301    let language = snapshot.language_at(location).map(|l| l.name());
22302    language_settings(language, file, cx).inlay_hints
22303}
22304
22305fn consume_contiguous_rows(
22306    contiguous_row_selections: &mut Vec<Selection<Point>>,
22307    selection: &Selection<Point>,
22308    display_map: &DisplaySnapshot,
22309    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22310) -> (MultiBufferRow, MultiBufferRow) {
22311    contiguous_row_selections.push(selection.clone());
22312    let start_row = starting_row(selection, display_map);
22313    let mut end_row = ending_row(selection, display_map);
22314
22315    while let Some(next_selection) = selections.peek() {
22316        if next_selection.start.row <= end_row.0 {
22317            end_row = ending_row(next_selection, display_map);
22318            contiguous_row_selections.push(selections.next().unwrap().clone());
22319        } else {
22320            break;
22321        }
22322    }
22323    (start_row, end_row)
22324}
22325
22326fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22327    if selection.start.column > 0 {
22328        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22329    } else {
22330        MultiBufferRow(selection.start.row)
22331    }
22332}
22333
22334fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22335    if next_selection.end.column > 0 || next_selection.is_empty() {
22336        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22337    } else {
22338        MultiBufferRow(next_selection.end.row)
22339    }
22340}
22341
22342impl EditorSnapshot {
22343    pub fn remote_selections_in_range<'a>(
22344        &'a self,
22345        range: &'a Range<Anchor>,
22346        collaboration_hub: &dyn CollaborationHub,
22347        cx: &'a App,
22348    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22349        let participant_names = collaboration_hub.user_names(cx);
22350        let participant_indices = collaboration_hub.user_participant_indices(cx);
22351        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22352        let collaborators_by_replica_id = collaborators_by_peer_id
22353            .values()
22354            .map(|collaborator| (collaborator.replica_id, collaborator))
22355            .collect::<HashMap<_, _>>();
22356        self.buffer_snapshot
22357            .selections_in_range(range, false)
22358            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22359                if replica_id == AGENT_REPLICA_ID {
22360                    Some(RemoteSelection {
22361                        replica_id,
22362                        selection,
22363                        cursor_shape,
22364                        line_mode,
22365                        collaborator_id: CollaboratorId::Agent,
22366                        user_name: Some("Agent".into()),
22367                        color: cx.theme().players().agent(),
22368                    })
22369                } else {
22370                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22371                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22372                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22373                    Some(RemoteSelection {
22374                        replica_id,
22375                        selection,
22376                        cursor_shape,
22377                        line_mode,
22378                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22379                        user_name,
22380                        color: if let Some(index) = participant_index {
22381                            cx.theme().players().color_for_participant(index.0)
22382                        } else {
22383                            cx.theme().players().absent()
22384                        },
22385                    })
22386                }
22387            })
22388    }
22389
22390    pub fn hunks_for_ranges(
22391        &self,
22392        ranges: impl IntoIterator<Item = Range<Point>>,
22393    ) -> Vec<MultiBufferDiffHunk> {
22394        let mut hunks = Vec::new();
22395        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22396            HashMap::default();
22397        for query_range in ranges {
22398            let query_rows =
22399                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22400            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22401                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22402            ) {
22403                // Include deleted hunks that are adjacent to the query range, because
22404                // otherwise they would be missed.
22405                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22406                if hunk.status().is_deleted() {
22407                    intersects_range |= hunk.row_range.start == query_rows.end;
22408                    intersects_range |= hunk.row_range.end == query_rows.start;
22409                }
22410                if intersects_range {
22411                    if !processed_buffer_rows
22412                        .entry(hunk.buffer_id)
22413                        .or_default()
22414                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22415                    {
22416                        continue;
22417                    }
22418                    hunks.push(hunk);
22419                }
22420            }
22421        }
22422
22423        hunks
22424    }
22425
22426    fn display_diff_hunks_for_rows<'a>(
22427        &'a self,
22428        display_rows: Range<DisplayRow>,
22429        folded_buffers: &'a HashSet<BufferId>,
22430    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22431        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22432        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22433
22434        self.buffer_snapshot
22435            .diff_hunks_in_range(buffer_start..buffer_end)
22436            .filter_map(|hunk| {
22437                if folded_buffers.contains(&hunk.buffer_id) {
22438                    return None;
22439                }
22440
22441                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22442                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22443
22444                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22445                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22446
22447                let display_hunk = if hunk_display_start.column() != 0 {
22448                    DisplayDiffHunk::Folded {
22449                        display_row: hunk_display_start.row(),
22450                    }
22451                } else {
22452                    let mut end_row = hunk_display_end.row();
22453                    if hunk_display_end.column() > 0 {
22454                        end_row.0 += 1;
22455                    }
22456                    let is_created_file = hunk.is_created_file();
22457                    DisplayDiffHunk::Unfolded {
22458                        status: hunk.status(),
22459                        diff_base_byte_range: hunk.diff_base_byte_range,
22460                        display_row_range: hunk_display_start.row()..end_row,
22461                        multi_buffer_range: Anchor::range_in_buffer(
22462                            hunk.excerpt_id,
22463                            hunk.buffer_id,
22464                            hunk.buffer_range,
22465                        ),
22466                        is_created_file,
22467                    }
22468                };
22469
22470                Some(display_hunk)
22471            })
22472    }
22473
22474    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22475        self.display_snapshot.buffer_snapshot.language_at(position)
22476    }
22477
22478    pub fn is_focused(&self) -> bool {
22479        self.is_focused
22480    }
22481
22482    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22483        self.placeholder_text.as_ref()
22484    }
22485
22486    pub fn scroll_position(&self) -> gpui::Point<f32> {
22487        self.scroll_anchor.scroll_position(&self.display_snapshot)
22488    }
22489
22490    fn gutter_dimensions(
22491        &self,
22492        font_id: FontId,
22493        font_size: Pixels,
22494        max_line_number_width: Pixels,
22495        cx: &App,
22496    ) -> Option<GutterDimensions> {
22497        if !self.show_gutter {
22498            return None;
22499        }
22500
22501        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22502        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22503
22504        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22505            matches!(
22506                ProjectSettings::get_global(cx).git.git_gutter,
22507                Some(GitGutterSetting::TrackedFiles)
22508            )
22509        });
22510        let gutter_settings = EditorSettings::get_global(cx).gutter;
22511        let show_line_numbers = self
22512            .show_line_numbers
22513            .unwrap_or(gutter_settings.line_numbers);
22514        let line_gutter_width = if show_line_numbers {
22515            // Avoid flicker-like gutter resizes when the line number gains another digit by
22516            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22517            let min_width_for_number_on_gutter =
22518                ch_advance * gutter_settings.min_line_number_digits as f32;
22519            max_line_number_width.max(min_width_for_number_on_gutter)
22520        } else {
22521            0.0.into()
22522        };
22523
22524        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22525        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22526
22527        let git_blame_entries_width =
22528            self.git_blame_gutter_max_author_length
22529                .map(|max_author_length| {
22530                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22531                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22532
22533                    /// The number of characters to dedicate to gaps and margins.
22534                    const SPACING_WIDTH: usize = 4;
22535
22536                    let max_char_count = max_author_length.min(renderer.max_author_length())
22537                        + ::git::SHORT_SHA_LENGTH
22538                        + MAX_RELATIVE_TIMESTAMP.len()
22539                        + SPACING_WIDTH;
22540
22541                    ch_advance * max_char_count
22542                });
22543
22544        let is_singleton = self.buffer_snapshot.is_singleton();
22545
22546        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22547        left_padding += if !is_singleton {
22548            ch_width * 4.0
22549        } else if show_runnables || show_breakpoints {
22550            ch_width * 3.0
22551        } else if show_git_gutter && show_line_numbers {
22552            ch_width * 2.0
22553        } else if show_git_gutter || show_line_numbers {
22554            ch_width
22555        } else {
22556            px(0.)
22557        };
22558
22559        let shows_folds = is_singleton && gutter_settings.folds;
22560
22561        let right_padding = if shows_folds && show_line_numbers {
22562            ch_width * 4.0
22563        } else if shows_folds || (!is_singleton && show_line_numbers) {
22564            ch_width * 3.0
22565        } else if show_line_numbers {
22566            ch_width
22567        } else {
22568            px(0.)
22569        };
22570
22571        Some(GutterDimensions {
22572            left_padding,
22573            right_padding,
22574            width: line_gutter_width + left_padding + right_padding,
22575            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22576            git_blame_entries_width,
22577        })
22578    }
22579
22580    pub fn render_crease_toggle(
22581        &self,
22582        buffer_row: MultiBufferRow,
22583        row_contains_cursor: bool,
22584        editor: Entity<Editor>,
22585        window: &mut Window,
22586        cx: &mut App,
22587    ) -> Option<AnyElement> {
22588        let folded = self.is_line_folded(buffer_row);
22589        let mut is_foldable = false;
22590
22591        if let Some(crease) = self
22592            .crease_snapshot
22593            .query_row(buffer_row, &self.buffer_snapshot)
22594        {
22595            is_foldable = true;
22596            match crease {
22597                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22598                    if let Some(render_toggle) = render_toggle {
22599                        let toggle_callback =
22600                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22601                                if folded {
22602                                    editor.update(cx, |editor, cx| {
22603                                        editor.fold_at(buffer_row, window, cx)
22604                                    });
22605                                } else {
22606                                    editor.update(cx, |editor, cx| {
22607                                        editor.unfold_at(buffer_row, window, cx)
22608                                    });
22609                                }
22610                            });
22611                        return Some((render_toggle)(
22612                            buffer_row,
22613                            folded,
22614                            toggle_callback,
22615                            window,
22616                            cx,
22617                        ));
22618                    }
22619                }
22620            }
22621        }
22622
22623        is_foldable |= self.starts_indent(buffer_row);
22624
22625        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22626            Some(
22627                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22628                    .toggle_state(folded)
22629                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22630                        if folded {
22631                            this.unfold_at(buffer_row, window, cx);
22632                        } else {
22633                            this.fold_at(buffer_row, window, cx);
22634                        }
22635                    }))
22636                    .into_any_element(),
22637            )
22638        } else {
22639            None
22640        }
22641    }
22642
22643    pub fn render_crease_trailer(
22644        &self,
22645        buffer_row: MultiBufferRow,
22646        window: &mut Window,
22647        cx: &mut App,
22648    ) -> Option<AnyElement> {
22649        let folded = self.is_line_folded(buffer_row);
22650        if let Crease::Inline { render_trailer, .. } = self
22651            .crease_snapshot
22652            .query_row(buffer_row, &self.buffer_snapshot)?
22653        {
22654            let render_trailer = render_trailer.as_ref()?;
22655            Some(render_trailer(buffer_row, folded, window, cx))
22656        } else {
22657            None
22658        }
22659    }
22660}
22661
22662impl Deref for EditorSnapshot {
22663    type Target = DisplaySnapshot;
22664
22665    fn deref(&self) -> &Self::Target {
22666        &self.display_snapshot
22667    }
22668}
22669
22670#[derive(Clone, Debug, PartialEq, Eq)]
22671pub enum EditorEvent {
22672    InputIgnored {
22673        text: Arc<str>,
22674    },
22675    InputHandled {
22676        utf16_range_to_replace: Option<Range<isize>>,
22677        text: Arc<str>,
22678    },
22679    ExcerptsAdded {
22680        buffer: Entity<Buffer>,
22681        predecessor: ExcerptId,
22682        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22683    },
22684    ExcerptsRemoved {
22685        ids: Vec<ExcerptId>,
22686        removed_buffer_ids: Vec<BufferId>,
22687    },
22688    BufferFoldToggled {
22689        ids: Vec<ExcerptId>,
22690        folded: bool,
22691    },
22692    ExcerptsEdited {
22693        ids: Vec<ExcerptId>,
22694    },
22695    ExcerptsExpanded {
22696        ids: Vec<ExcerptId>,
22697    },
22698    BufferEdited,
22699    Edited {
22700        transaction_id: clock::Lamport,
22701    },
22702    Reparsed(BufferId),
22703    Focused,
22704    FocusedIn,
22705    Blurred,
22706    DirtyChanged,
22707    Saved,
22708    TitleChanged,
22709    DiffBaseChanged,
22710    SelectionsChanged {
22711        local: bool,
22712    },
22713    ScrollPositionChanged {
22714        local: bool,
22715        autoscroll: bool,
22716    },
22717    Closed,
22718    TransactionUndone {
22719        transaction_id: clock::Lamport,
22720    },
22721    TransactionBegun {
22722        transaction_id: clock::Lamport,
22723    },
22724    Reloaded,
22725    CursorShapeChanged,
22726    PushedToNavHistory {
22727        anchor: Anchor,
22728        is_deactivate: bool,
22729    },
22730}
22731
22732impl EventEmitter<EditorEvent> for Editor {}
22733
22734impl Focusable for Editor {
22735    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22736        self.focus_handle.clone()
22737    }
22738}
22739
22740impl Render for Editor {
22741    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22742        let settings = ThemeSettings::get_global(cx);
22743
22744        let mut text_style = match self.mode {
22745            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22746                color: cx.theme().colors().editor_foreground,
22747                font_family: settings.ui_font.family.clone(),
22748                font_features: settings.ui_font.features.clone(),
22749                font_fallbacks: settings.ui_font.fallbacks.clone(),
22750                font_size: rems(0.875).into(),
22751                font_weight: settings.ui_font.weight,
22752                line_height: relative(settings.buffer_line_height.value()),
22753                ..Default::default()
22754            },
22755            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22756                color: cx.theme().colors().editor_foreground,
22757                font_family: settings.buffer_font.family.clone(),
22758                font_features: settings.buffer_font.features.clone(),
22759                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22760                font_size: settings.buffer_font_size(cx).into(),
22761                font_weight: settings.buffer_font.weight,
22762                line_height: relative(settings.buffer_line_height.value()),
22763                ..Default::default()
22764            },
22765        };
22766        if let Some(text_style_refinement) = &self.text_style_refinement {
22767            text_style.refine(text_style_refinement)
22768        }
22769
22770        let background = match self.mode {
22771            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22772            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22773            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22774            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22775        };
22776
22777        EditorElement::new(
22778            &cx.entity(),
22779            EditorStyle {
22780                background,
22781                border: cx.theme().colors().border,
22782                local_player: cx.theme().players().local(),
22783                text: text_style,
22784                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22785                syntax: cx.theme().syntax().clone(),
22786                status: cx.theme().status().clone(),
22787                inlay_hints_style: make_inlay_hints_style(cx),
22788                inline_completion_styles: make_suggestion_styles(cx),
22789                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22790                show_underlines: self.diagnostics_enabled(),
22791            },
22792        )
22793    }
22794}
22795
22796impl EntityInputHandler for Editor {
22797    fn text_for_range(
22798        &mut self,
22799        range_utf16: Range<usize>,
22800        adjusted_range: &mut Option<Range<usize>>,
22801        _: &mut Window,
22802        cx: &mut Context<Self>,
22803    ) -> Option<String> {
22804        let snapshot = self.buffer.read(cx).read(cx);
22805        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22806        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22807        if (start.0..end.0) != range_utf16 {
22808            adjusted_range.replace(start.0..end.0);
22809        }
22810        Some(snapshot.text_for_range(start..end).collect())
22811    }
22812
22813    fn selected_text_range(
22814        &mut self,
22815        ignore_disabled_input: bool,
22816        _: &mut Window,
22817        cx: &mut Context<Self>,
22818    ) -> Option<UTF16Selection> {
22819        // Prevent the IME menu from appearing when holding down an alphabetic key
22820        // while input is disabled.
22821        if !ignore_disabled_input && !self.input_enabled {
22822            return None;
22823        }
22824
22825        let selection = self.selections.newest::<OffsetUtf16>(cx);
22826        let range = selection.range();
22827
22828        Some(UTF16Selection {
22829            range: range.start.0..range.end.0,
22830            reversed: selection.reversed,
22831        })
22832    }
22833
22834    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22835        let snapshot = self.buffer.read(cx).read(cx);
22836        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22837        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22838    }
22839
22840    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22841        self.clear_highlights::<InputComposition>(cx);
22842        self.ime_transaction.take();
22843    }
22844
22845    fn replace_text_in_range(
22846        &mut self,
22847        range_utf16: Option<Range<usize>>,
22848        text: &str,
22849        window: &mut Window,
22850        cx: &mut Context<Self>,
22851    ) {
22852        if !self.input_enabled {
22853            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22854            return;
22855        }
22856
22857        self.transact(window, cx, |this, window, cx| {
22858            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22859                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22860                Some(this.selection_replacement_ranges(range_utf16, cx))
22861            } else {
22862                this.marked_text_ranges(cx)
22863            };
22864
22865            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22866                let newest_selection_id = this.selections.newest_anchor().id;
22867                this.selections
22868                    .all::<OffsetUtf16>(cx)
22869                    .iter()
22870                    .zip(ranges_to_replace.iter())
22871                    .find_map(|(selection, range)| {
22872                        if selection.id == newest_selection_id {
22873                            Some(
22874                                (range.start.0 as isize - selection.head().0 as isize)
22875                                    ..(range.end.0 as isize - selection.head().0 as isize),
22876                            )
22877                        } else {
22878                            None
22879                        }
22880                    })
22881            });
22882
22883            cx.emit(EditorEvent::InputHandled {
22884                utf16_range_to_replace: range_to_replace,
22885                text: text.into(),
22886            });
22887
22888            if let Some(new_selected_ranges) = new_selected_ranges {
22889                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22890                    selections.select_ranges(new_selected_ranges)
22891                });
22892                this.backspace(&Default::default(), window, cx);
22893            }
22894
22895            this.handle_input(text, window, cx);
22896        });
22897
22898        if let Some(transaction) = self.ime_transaction {
22899            self.buffer.update(cx, |buffer, cx| {
22900                buffer.group_until_transaction(transaction, cx);
22901            });
22902        }
22903
22904        self.unmark_text(window, cx);
22905    }
22906
22907    fn replace_and_mark_text_in_range(
22908        &mut self,
22909        range_utf16: Option<Range<usize>>,
22910        text: &str,
22911        new_selected_range_utf16: Option<Range<usize>>,
22912        window: &mut Window,
22913        cx: &mut Context<Self>,
22914    ) {
22915        if !self.input_enabled {
22916            return;
22917        }
22918
22919        let transaction = self.transact(window, cx, |this, window, cx| {
22920            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22921                let snapshot = this.buffer.read(cx).read(cx);
22922                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22923                    for marked_range in &mut marked_ranges {
22924                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22925                        marked_range.start.0 += relative_range_utf16.start;
22926                        marked_range.start =
22927                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22928                        marked_range.end =
22929                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22930                    }
22931                }
22932                Some(marked_ranges)
22933            } else if let Some(range_utf16) = range_utf16 {
22934                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22935                Some(this.selection_replacement_ranges(range_utf16, cx))
22936            } else {
22937                None
22938            };
22939
22940            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22941                let newest_selection_id = this.selections.newest_anchor().id;
22942                this.selections
22943                    .all::<OffsetUtf16>(cx)
22944                    .iter()
22945                    .zip(ranges_to_replace.iter())
22946                    .find_map(|(selection, range)| {
22947                        if selection.id == newest_selection_id {
22948                            Some(
22949                                (range.start.0 as isize - selection.head().0 as isize)
22950                                    ..(range.end.0 as isize - selection.head().0 as isize),
22951                            )
22952                        } else {
22953                            None
22954                        }
22955                    })
22956            });
22957
22958            cx.emit(EditorEvent::InputHandled {
22959                utf16_range_to_replace: range_to_replace,
22960                text: text.into(),
22961            });
22962
22963            if let Some(ranges) = ranges_to_replace {
22964                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22965                    s.select_ranges(ranges)
22966                });
22967            }
22968
22969            let marked_ranges = {
22970                let snapshot = this.buffer.read(cx).read(cx);
22971                this.selections
22972                    .disjoint_anchors()
22973                    .iter()
22974                    .map(|selection| {
22975                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22976                    })
22977                    .collect::<Vec<_>>()
22978            };
22979
22980            if text.is_empty() {
22981                this.unmark_text(window, cx);
22982            } else {
22983                this.highlight_text::<InputComposition>(
22984                    marked_ranges.clone(),
22985                    HighlightStyle {
22986                        underline: Some(UnderlineStyle {
22987                            thickness: px(1.),
22988                            color: None,
22989                            wavy: false,
22990                        }),
22991                        ..Default::default()
22992                    },
22993                    cx,
22994                );
22995            }
22996
22997            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22998            let use_autoclose = this.use_autoclose;
22999            let use_auto_surround = this.use_auto_surround;
23000            this.set_use_autoclose(false);
23001            this.set_use_auto_surround(false);
23002            this.handle_input(text, window, cx);
23003            this.set_use_autoclose(use_autoclose);
23004            this.set_use_auto_surround(use_auto_surround);
23005
23006            if let Some(new_selected_range) = new_selected_range_utf16 {
23007                let snapshot = this.buffer.read(cx).read(cx);
23008                let new_selected_ranges = marked_ranges
23009                    .into_iter()
23010                    .map(|marked_range| {
23011                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23012                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23013                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23014                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23015                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23016                    })
23017                    .collect::<Vec<_>>();
23018
23019                drop(snapshot);
23020                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23021                    selections.select_ranges(new_selected_ranges)
23022                });
23023            }
23024        });
23025
23026        self.ime_transaction = self.ime_transaction.or(transaction);
23027        if let Some(transaction) = self.ime_transaction {
23028            self.buffer.update(cx, |buffer, cx| {
23029                buffer.group_until_transaction(transaction, cx);
23030            });
23031        }
23032
23033        if self.text_highlights::<InputComposition>(cx).is_none() {
23034            self.ime_transaction.take();
23035        }
23036    }
23037
23038    fn bounds_for_range(
23039        &mut self,
23040        range_utf16: Range<usize>,
23041        element_bounds: gpui::Bounds<Pixels>,
23042        window: &mut Window,
23043        cx: &mut Context<Self>,
23044    ) -> Option<gpui::Bounds<Pixels>> {
23045        let text_layout_details = self.text_layout_details(window);
23046        let CharacterDimensions {
23047            em_width,
23048            em_advance,
23049            line_height,
23050        } = self.character_dimensions(window);
23051
23052        let snapshot = self.snapshot(window, cx);
23053        let scroll_position = snapshot.scroll_position();
23054        let scroll_left = scroll_position.x * em_advance;
23055
23056        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23057        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23058            + self.gutter_dimensions.full_width();
23059        let y = line_height * (start.row().as_f32() - scroll_position.y);
23060
23061        Some(Bounds {
23062            origin: element_bounds.origin + point(x, y),
23063            size: size(em_width, line_height),
23064        })
23065    }
23066
23067    fn character_index_for_point(
23068        &mut self,
23069        point: gpui::Point<Pixels>,
23070        _window: &mut Window,
23071        _cx: &mut Context<Self>,
23072    ) -> Option<usize> {
23073        let position_map = self.last_position_map.as_ref()?;
23074        if !position_map.text_hitbox.contains(&point) {
23075            return None;
23076        }
23077        let display_point = position_map.point_for_position(point).previous_valid;
23078        let anchor = position_map
23079            .snapshot
23080            .display_point_to_anchor(display_point, Bias::Left);
23081        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23082        Some(utf16_offset.0)
23083    }
23084}
23085
23086trait SelectionExt {
23087    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23088    fn spanned_rows(
23089        &self,
23090        include_end_if_at_line_start: bool,
23091        map: &DisplaySnapshot,
23092    ) -> Range<MultiBufferRow>;
23093}
23094
23095impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23096    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23097        let start = self
23098            .start
23099            .to_point(&map.buffer_snapshot)
23100            .to_display_point(map);
23101        let end = self
23102            .end
23103            .to_point(&map.buffer_snapshot)
23104            .to_display_point(map);
23105        if self.reversed {
23106            end..start
23107        } else {
23108            start..end
23109        }
23110    }
23111
23112    fn spanned_rows(
23113        &self,
23114        include_end_if_at_line_start: bool,
23115        map: &DisplaySnapshot,
23116    ) -> Range<MultiBufferRow> {
23117        let start = self.start.to_point(&map.buffer_snapshot);
23118        let mut end = self.end.to_point(&map.buffer_snapshot);
23119        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23120            end.row -= 1;
23121        }
23122
23123        let buffer_start = map.prev_line_boundary(start).0;
23124        let buffer_end = map.next_line_boundary(end).0;
23125        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23126    }
23127}
23128
23129impl<T: InvalidationRegion> InvalidationStack<T> {
23130    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23131    where
23132        S: Clone + ToOffset,
23133    {
23134        while let Some(region) = self.last() {
23135            let all_selections_inside_invalidation_ranges =
23136                if selections.len() == region.ranges().len() {
23137                    selections
23138                        .iter()
23139                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23140                        .all(|(selection, invalidation_range)| {
23141                            let head = selection.head().to_offset(buffer);
23142                            invalidation_range.start <= head && invalidation_range.end >= head
23143                        })
23144                } else {
23145                    false
23146                };
23147
23148            if all_selections_inside_invalidation_ranges {
23149                break;
23150            } else {
23151                self.pop();
23152            }
23153        }
23154    }
23155}
23156
23157impl<T> Default for InvalidationStack<T> {
23158    fn default() -> Self {
23159        Self(Default::default())
23160    }
23161}
23162
23163impl<T> Deref for InvalidationStack<T> {
23164    type Target = Vec<T>;
23165
23166    fn deref(&self) -> &Self::Target {
23167        &self.0
23168    }
23169}
23170
23171impl<T> DerefMut for InvalidationStack<T> {
23172    fn deref_mut(&mut self) -> &mut Self::Target {
23173        &mut self.0
23174    }
23175}
23176
23177impl InvalidationRegion for SnippetState {
23178    fn ranges(&self) -> &[Range<Anchor>] {
23179        &self.ranges[self.active_index]
23180    }
23181}
23182
23183fn inline_completion_edit_text(
23184    current_snapshot: &BufferSnapshot,
23185    edits: &[(Range<Anchor>, String)],
23186    edit_preview: &EditPreview,
23187    include_deletions: bool,
23188    cx: &App,
23189) -> HighlightedText {
23190    let edits = edits
23191        .iter()
23192        .map(|(anchor, text)| {
23193            (
23194                anchor.start.text_anchor..anchor.end.text_anchor,
23195                text.clone(),
23196            )
23197        })
23198        .collect::<Vec<_>>();
23199
23200    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23201}
23202
23203pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23204    match severity {
23205        lsp::DiagnosticSeverity::ERROR => colors.error,
23206        lsp::DiagnosticSeverity::WARNING => colors.warning,
23207        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23208        lsp::DiagnosticSeverity::HINT => colors.info,
23209        _ => colors.ignored,
23210    }
23211}
23212
23213pub fn styled_runs_for_code_label<'a>(
23214    label: &'a CodeLabel,
23215    syntax_theme: &'a theme::SyntaxTheme,
23216) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23217    let fade_out = HighlightStyle {
23218        fade_out: Some(0.35),
23219        ..Default::default()
23220    };
23221
23222    let mut prev_end = label.filter_range.end;
23223    label
23224        .runs
23225        .iter()
23226        .enumerate()
23227        .flat_map(move |(ix, (range, highlight_id))| {
23228            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23229                style
23230            } else {
23231                return Default::default();
23232            };
23233            let mut muted_style = style;
23234            muted_style.highlight(fade_out);
23235
23236            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23237            if range.start >= label.filter_range.end {
23238                if range.start > prev_end {
23239                    runs.push((prev_end..range.start, fade_out));
23240                }
23241                runs.push((range.clone(), muted_style));
23242            } else if range.end <= label.filter_range.end {
23243                runs.push((range.clone(), style));
23244            } else {
23245                runs.push((range.start..label.filter_range.end, style));
23246                runs.push((label.filter_range.end..range.end, muted_style));
23247            }
23248            prev_end = cmp::max(prev_end, range.end);
23249
23250            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23251                runs.push((prev_end..label.text.len(), fade_out));
23252            }
23253
23254            runs
23255        })
23256}
23257
23258pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23259    let mut prev_index = 0;
23260    let mut prev_codepoint: Option<char> = None;
23261    text.char_indices()
23262        .chain([(text.len(), '\0')])
23263        .filter_map(move |(index, codepoint)| {
23264            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23265            let is_boundary = index == text.len()
23266                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23267                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23268            if is_boundary {
23269                let chunk = &text[prev_index..index];
23270                prev_index = index;
23271                Some(chunk)
23272            } else {
23273                None
23274            }
23275        })
23276}
23277
23278pub trait RangeToAnchorExt: Sized {
23279    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23280
23281    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23282        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23283        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23284    }
23285}
23286
23287impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23288    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23289        let start_offset = self.start.to_offset(snapshot);
23290        let end_offset = self.end.to_offset(snapshot);
23291        if start_offset == end_offset {
23292            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23293        } else {
23294            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23295        }
23296    }
23297}
23298
23299pub trait RowExt {
23300    fn as_f32(&self) -> f32;
23301
23302    fn next_row(&self) -> Self;
23303
23304    fn previous_row(&self) -> Self;
23305
23306    fn minus(&self, other: Self) -> u32;
23307}
23308
23309impl RowExt for DisplayRow {
23310    fn as_f32(&self) -> f32 {
23311        self.0 as f32
23312    }
23313
23314    fn next_row(&self) -> Self {
23315        Self(self.0 + 1)
23316    }
23317
23318    fn previous_row(&self) -> Self {
23319        Self(self.0.saturating_sub(1))
23320    }
23321
23322    fn minus(&self, other: Self) -> u32 {
23323        self.0 - other.0
23324    }
23325}
23326
23327impl RowExt for MultiBufferRow {
23328    fn as_f32(&self) -> f32 {
23329        self.0 as f32
23330    }
23331
23332    fn next_row(&self) -> Self {
23333        Self(self.0 + 1)
23334    }
23335
23336    fn previous_row(&self) -> Self {
23337        Self(self.0.saturating_sub(1))
23338    }
23339
23340    fn minus(&self, other: Self) -> u32 {
23341        self.0 - other.0
23342    }
23343}
23344
23345trait RowRangeExt {
23346    type Row;
23347
23348    fn len(&self) -> usize;
23349
23350    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23351}
23352
23353impl RowRangeExt for Range<MultiBufferRow> {
23354    type Row = MultiBufferRow;
23355
23356    fn len(&self) -> usize {
23357        (self.end.0 - self.start.0) as usize
23358    }
23359
23360    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23361        (self.start.0..self.end.0).map(MultiBufferRow)
23362    }
23363}
23364
23365impl RowRangeExt for Range<DisplayRow> {
23366    type Row = DisplayRow;
23367
23368    fn len(&self) -> usize {
23369        (self.end.0 - self.start.0) as usize
23370    }
23371
23372    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23373        (self.start.0..self.end.0).map(DisplayRow)
23374    }
23375}
23376
23377/// If select range has more than one line, we
23378/// just point the cursor to range.start.
23379fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23380    if range.start.row == range.end.row {
23381        range
23382    } else {
23383        range.start..range.start
23384    }
23385}
23386pub struct KillRing(ClipboardItem);
23387impl Global for KillRing {}
23388
23389const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23390
23391enum BreakpointPromptEditAction {
23392    Log,
23393    Condition,
23394    HitCondition,
23395}
23396
23397struct BreakpointPromptEditor {
23398    pub(crate) prompt: Entity<Editor>,
23399    editor: WeakEntity<Editor>,
23400    breakpoint_anchor: Anchor,
23401    breakpoint: Breakpoint,
23402    edit_action: BreakpointPromptEditAction,
23403    block_ids: HashSet<CustomBlockId>,
23404    editor_margins: Arc<Mutex<EditorMargins>>,
23405    _subscriptions: Vec<Subscription>,
23406}
23407
23408impl BreakpointPromptEditor {
23409    const MAX_LINES: u8 = 4;
23410
23411    fn new(
23412        editor: WeakEntity<Editor>,
23413        breakpoint_anchor: Anchor,
23414        breakpoint: Breakpoint,
23415        edit_action: BreakpointPromptEditAction,
23416        window: &mut Window,
23417        cx: &mut Context<Self>,
23418    ) -> Self {
23419        let base_text = match edit_action {
23420            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23421            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23422            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23423        }
23424        .map(|msg| msg.to_string())
23425        .unwrap_or_default();
23426
23427        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23428        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23429
23430        let prompt = cx.new(|cx| {
23431            let mut prompt = Editor::new(
23432                EditorMode::AutoHeight {
23433                    min_lines: 1,
23434                    max_lines: Some(Self::MAX_LINES as usize),
23435                },
23436                buffer,
23437                None,
23438                window,
23439                cx,
23440            );
23441            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23442            prompt.set_show_cursor_when_unfocused(false, cx);
23443            prompt.set_placeholder_text(
23444                match edit_action {
23445                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23446                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23447                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23448                },
23449                cx,
23450            );
23451
23452            prompt
23453        });
23454
23455        Self {
23456            prompt,
23457            editor,
23458            breakpoint_anchor,
23459            breakpoint,
23460            edit_action,
23461            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23462            block_ids: Default::default(),
23463            _subscriptions: vec![],
23464        }
23465    }
23466
23467    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23468        self.block_ids.extend(block_ids)
23469    }
23470
23471    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23472        if let Some(editor) = self.editor.upgrade() {
23473            let message = self
23474                .prompt
23475                .read(cx)
23476                .buffer
23477                .read(cx)
23478                .as_singleton()
23479                .expect("A multi buffer in breakpoint prompt isn't possible")
23480                .read(cx)
23481                .as_rope()
23482                .to_string();
23483
23484            editor.update(cx, |editor, cx| {
23485                editor.edit_breakpoint_at_anchor(
23486                    self.breakpoint_anchor,
23487                    self.breakpoint.clone(),
23488                    match self.edit_action {
23489                        BreakpointPromptEditAction::Log => {
23490                            BreakpointEditAction::EditLogMessage(message.into())
23491                        }
23492                        BreakpointPromptEditAction::Condition => {
23493                            BreakpointEditAction::EditCondition(message.into())
23494                        }
23495                        BreakpointPromptEditAction::HitCondition => {
23496                            BreakpointEditAction::EditHitCondition(message.into())
23497                        }
23498                    },
23499                    cx,
23500                );
23501
23502                editor.remove_blocks(self.block_ids.clone(), None, cx);
23503                cx.focus_self(window);
23504            });
23505        }
23506    }
23507
23508    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23509        self.editor
23510            .update(cx, |editor, cx| {
23511                editor.remove_blocks(self.block_ids.clone(), None, cx);
23512                window.focus(&editor.focus_handle);
23513            })
23514            .log_err();
23515    }
23516
23517    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23518        let settings = ThemeSettings::get_global(cx);
23519        let text_style = TextStyle {
23520            color: if self.prompt.read(cx).read_only(cx) {
23521                cx.theme().colors().text_disabled
23522            } else {
23523                cx.theme().colors().text
23524            },
23525            font_family: settings.buffer_font.family.clone(),
23526            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23527            font_size: settings.buffer_font_size(cx).into(),
23528            font_weight: settings.buffer_font.weight,
23529            line_height: relative(settings.buffer_line_height.value()),
23530            ..Default::default()
23531        };
23532        EditorElement::new(
23533            &self.prompt,
23534            EditorStyle {
23535                background: cx.theme().colors().editor_background,
23536                local_player: cx.theme().players().local(),
23537                text: text_style,
23538                ..Default::default()
23539            },
23540        )
23541    }
23542}
23543
23544impl Render for BreakpointPromptEditor {
23545    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23546        let editor_margins = *self.editor_margins.lock();
23547        let gutter_dimensions = editor_margins.gutter;
23548        h_flex()
23549            .key_context("Editor")
23550            .bg(cx.theme().colors().editor_background)
23551            .border_y_1()
23552            .border_color(cx.theme().status().info_border)
23553            .size_full()
23554            .py(window.line_height() / 2.5)
23555            .on_action(cx.listener(Self::confirm))
23556            .on_action(cx.listener(Self::cancel))
23557            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23558            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23559    }
23560}
23561
23562impl Focusable for BreakpointPromptEditor {
23563    fn focus_handle(&self, cx: &App) -> FocusHandle {
23564        self.prompt.focus_handle(cx)
23565    }
23566}
23567
23568fn all_edits_insertions_or_deletions(
23569    edits: &Vec<(Range<Anchor>, String)>,
23570    snapshot: &MultiBufferSnapshot,
23571) -> bool {
23572    let mut all_insertions = true;
23573    let mut all_deletions = true;
23574
23575    for (range, new_text) in edits.iter() {
23576        let range_is_empty = range.to_offset(&snapshot).is_empty();
23577        let text_is_empty = new_text.is_empty();
23578
23579        if range_is_empty != text_is_empty {
23580            if range_is_empty {
23581                all_deletions = false;
23582            } else {
23583                all_insertions = false;
23584            }
23585        } else {
23586            return false;
23587        }
23588
23589        if !all_insertions && !all_deletions {
23590            return false;
23591        }
23592    }
23593    all_insertions || all_deletions
23594}
23595
23596struct MissingEditPredictionKeybindingTooltip;
23597
23598impl Render for MissingEditPredictionKeybindingTooltip {
23599    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23600        ui::tooltip_container(window, cx, |container, _, cx| {
23601            container
23602                .flex_shrink_0()
23603                .max_w_80()
23604                .min_h(rems_from_px(124.))
23605                .justify_between()
23606                .child(
23607                    v_flex()
23608                        .flex_1()
23609                        .text_ui_sm(cx)
23610                        .child(Label::new("Conflict with Accept Keybinding"))
23611                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23612                )
23613                .child(
23614                    h_flex()
23615                        .pb_1()
23616                        .gap_1()
23617                        .items_end()
23618                        .w_full()
23619                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23620                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23621                        }))
23622                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23623                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23624                        })),
23625                )
23626        })
23627    }
23628}
23629
23630#[derive(Debug, Clone, Copy, PartialEq)]
23631pub struct LineHighlight {
23632    pub background: Background,
23633    pub border: Option<gpui::Hsla>,
23634    pub include_gutter: bool,
23635    pub type_id: Option<TypeId>,
23636}
23637
23638struct LineManipulationResult {
23639    pub new_text: String,
23640    pub line_count_before: usize,
23641    pub line_count_after: usize,
23642}
23643
23644fn render_diff_hunk_controls(
23645    row: u32,
23646    status: &DiffHunkStatus,
23647    hunk_range: Range<Anchor>,
23648    is_created_file: bool,
23649    line_height: Pixels,
23650    editor: &Entity<Editor>,
23651    _window: &mut Window,
23652    cx: &mut App,
23653) -> AnyElement {
23654    h_flex()
23655        .h(line_height)
23656        .mr_1()
23657        .gap_1()
23658        .px_0p5()
23659        .pb_1()
23660        .border_x_1()
23661        .border_b_1()
23662        .border_color(cx.theme().colors().border_variant)
23663        .rounded_b_lg()
23664        .bg(cx.theme().colors().editor_background)
23665        .gap_1()
23666        .block_mouse_except_scroll()
23667        .shadow_md()
23668        .child(if status.has_secondary_hunk() {
23669            Button::new(("stage", row as u64), "Stage")
23670                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23671                .tooltip({
23672                    let focus_handle = editor.focus_handle(cx);
23673                    move |window, cx| {
23674                        Tooltip::for_action_in(
23675                            "Stage Hunk",
23676                            &::git::ToggleStaged,
23677                            &focus_handle,
23678                            window,
23679                            cx,
23680                        )
23681                    }
23682                })
23683                .on_click({
23684                    let editor = editor.clone();
23685                    move |_event, _window, cx| {
23686                        editor.update(cx, |editor, cx| {
23687                            editor.stage_or_unstage_diff_hunks(
23688                                true,
23689                                vec![hunk_range.start..hunk_range.start],
23690                                cx,
23691                            );
23692                        });
23693                    }
23694                })
23695        } else {
23696            Button::new(("unstage", row as u64), "Unstage")
23697                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23698                .tooltip({
23699                    let focus_handle = editor.focus_handle(cx);
23700                    move |window, cx| {
23701                        Tooltip::for_action_in(
23702                            "Unstage Hunk",
23703                            &::git::ToggleStaged,
23704                            &focus_handle,
23705                            window,
23706                            cx,
23707                        )
23708                    }
23709                })
23710                .on_click({
23711                    let editor = editor.clone();
23712                    move |_event, _window, cx| {
23713                        editor.update(cx, |editor, cx| {
23714                            editor.stage_or_unstage_diff_hunks(
23715                                false,
23716                                vec![hunk_range.start..hunk_range.start],
23717                                cx,
23718                            );
23719                        });
23720                    }
23721                })
23722        })
23723        .child(
23724            Button::new(("restore", row as u64), "Restore")
23725                .tooltip({
23726                    let focus_handle = editor.focus_handle(cx);
23727                    move |window, cx| {
23728                        Tooltip::for_action_in(
23729                            "Restore Hunk",
23730                            &::git::Restore,
23731                            &focus_handle,
23732                            window,
23733                            cx,
23734                        )
23735                    }
23736                })
23737                .on_click({
23738                    let editor = editor.clone();
23739                    move |_event, window, cx| {
23740                        editor.update(cx, |editor, cx| {
23741                            let snapshot = editor.snapshot(window, cx);
23742                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23743                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23744                        });
23745                    }
23746                })
23747                .disabled(is_created_file),
23748        )
23749        .when(
23750            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23751            |el| {
23752                el.child(
23753                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23754                        .shape(IconButtonShape::Square)
23755                        .icon_size(IconSize::Small)
23756                        // .disabled(!has_multiple_hunks)
23757                        .tooltip({
23758                            let focus_handle = editor.focus_handle(cx);
23759                            move |window, cx| {
23760                                Tooltip::for_action_in(
23761                                    "Next Hunk",
23762                                    &GoToHunk,
23763                                    &focus_handle,
23764                                    window,
23765                                    cx,
23766                                )
23767                            }
23768                        })
23769                        .on_click({
23770                            let editor = editor.clone();
23771                            move |_event, window, cx| {
23772                                editor.update(cx, |editor, cx| {
23773                                    let snapshot = editor.snapshot(window, cx);
23774                                    let position =
23775                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23776                                    editor.go_to_hunk_before_or_after_position(
23777                                        &snapshot,
23778                                        position,
23779                                        Direction::Next,
23780                                        window,
23781                                        cx,
23782                                    );
23783                                    editor.expand_selected_diff_hunks(cx);
23784                                });
23785                            }
23786                        }),
23787                )
23788                .child(
23789                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23790                        .shape(IconButtonShape::Square)
23791                        .icon_size(IconSize::Small)
23792                        // .disabled(!has_multiple_hunks)
23793                        .tooltip({
23794                            let focus_handle = editor.focus_handle(cx);
23795                            move |window, cx| {
23796                                Tooltip::for_action_in(
23797                                    "Previous Hunk",
23798                                    &GoToPreviousHunk,
23799                                    &focus_handle,
23800                                    window,
23801                                    cx,
23802                                )
23803                            }
23804                        })
23805                        .on_click({
23806                            let editor = editor.clone();
23807                            move |_event, window, cx| {
23808                                editor.update(cx, |editor, cx| {
23809                                    let snapshot = editor.snapshot(window, cx);
23810                                    let point =
23811                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23812                                    editor.go_to_hunk_before_or_after_position(
23813                                        &snapshot,
23814                                        point,
23815                                        Direction::Prev,
23816                                        window,
23817                                        cx,
23818                                    );
23819                                    editor.expand_selected_diff_hunks(cx);
23820                                });
23821                            }
23822                        }),
23823                )
23824            },
23825        )
23826        .into_any_element()
23827}