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 blame_entry_tooltip;
   17mod blink_manager;
   18mod clangd_ext;
   19mod debounced_delay;
   20pub mod display_map;
   21mod editor_settings;
   22mod editor_settings_controls;
   23mod element;
   24mod git;
   25mod highlight_matching_bracket;
   26mod hover_links;
   27mod hover_popover;
   28mod hunk_diff;
   29mod indent_guides;
   30mod inlay_hint_cache;
   31mod inline_completion_provider;
   32pub mod items;
   33mod linked_editing_ranges;
   34mod lsp_ext;
   35mod mouse_context_menu;
   36pub mod movement;
   37mod persistence;
   38mod proposed_changes_editor;
   39mod rust_analyzer_ext;
   40pub mod scroll;
   41mod selections_collection;
   42pub mod tasks;
   43
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50use ::git::diff::DiffHunkStatus;
   51pub(crate) use actions::*;
   52pub use actions::{OpenExcerpts, OpenExcerptsSplit};
   53use aho_corasick::AhoCorasick;
   54use anyhow::{anyhow, Context as _, Result};
   55use blink_manager::BlinkManager;
   56use client::{Collaborator, ParticipantIndex};
   57use clock::ReplicaId;
   58use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
   59use convert_case::{Case, Casing};
   60use debounced_delay::DebouncedDelay;
   61use display_map::*;
   62pub use display_map::{DisplayPoint, FoldPlaceholder};
   63pub use editor_settings::{
   64    CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar,
   65};
   66pub use editor_settings_controls::*;
   67use element::LineWithInvisibles;
   68pub use element::{
   69    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   70};
   71use futures::{future, FutureExt};
   72use fuzzy::{StringMatch, StringMatchCandidate};
   73use git::blame::GitBlame;
   74use gpui::{
   75    div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
   76    AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
   77    ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent,
   78    FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext,
   79    ListSizingBehavior, Model, ModelContext, MouseButton, PaintQuad, ParentElement, Pixels, Render,
   80    ScrollStrategy, SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task,
   81    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, View,
   82    ViewContext, ViewInputHandler, VisualContext, WeakFocusHandle, WeakView, WindowContext,
   83};
   84use highlight_matching_bracket::refresh_matching_bracket_highlights;
   85use hover_popover::{hide_hover, HoverState};
   86pub(crate) use hunk_diff::HoveredHunk;
   87use hunk_diff::{diff_hunk_to_display, ExpandedHunks};
   88use indent_guides::ActiveIndentGuidesState;
   89use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
   90pub use inline_completion_provider::*;
   91pub use items::MAX_TAB_TITLE_LEN;
   92use itertools::Itertools;
   93use language::{
   94    language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
   95    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
   96    CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
   97    Point, Selection, SelectionGoal, TransactionId,
   98};
   99use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
  100use linked_editing_ranges::refresh_linked_ranges;
  101pub use proposed_changes_editor::{
  102    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  103};
  104use similar::{ChangeTag, TextDiff};
  105use std::iter::Peekable;
  106use task::{ResolvedTask, TaskTemplate, TaskVariables};
  107
  108use hover_links::{find_file, HoverLink, HoveredLinkState, InlayHighlight};
  109pub use lsp::CompletionContext;
  110use lsp::{
  111    CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat,
  112    LanguageServerId, LanguageServerName,
  113};
  114use mouse_context_menu::MouseContextMenu;
  115use movement::TextLayoutDetails;
  116pub use multi_buffer::{
  117    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
  118    ToPoint,
  119};
  120use multi_buffer::{
  121    ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow, ToOffsetUtf16,
  122};
  123use ordered_float::OrderedFloat;
  124use parking_lot::{Mutex, RwLock};
  125use project::{
  126    lsp_store::{FormatTarget, FormatTrigger},
  127    project_settings::{GitGutterSetting, ProjectSettings},
  128    CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Item, Location,
  129    LocationLink, Project, ProjectTransaction, TaskSourceKind,
  130};
  131use rand::prelude::*;
  132use rpc::{proto::*, ErrorExt};
  133use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  134use selections_collection::{
  135    resolve_selections, MutableSelectionsCollection, SelectionsCollection,
  136};
  137use serde::{Deserialize, Serialize};
  138use settings::{update_settings_file, Settings, SettingsLocation, SettingsStore};
  139use smallvec::SmallVec;
  140use snippet::Snippet;
  141use std::{
  142    any::TypeId,
  143    borrow::Cow,
  144    cell::RefCell,
  145    cmp::{self, Ordering, Reverse},
  146    mem,
  147    num::NonZeroU32,
  148    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  149    path::{Path, PathBuf},
  150    rc::Rc,
  151    sync::Arc,
  152    time::{Duration, Instant},
  153};
  154pub use sum_tree::Bias;
  155use sum_tree::TreeMap;
  156use text::{BufferId, OffsetUtf16, Rope};
  157use theme::{
  158    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  159    ThemeColors, ThemeSettings,
  160};
  161use ui::{
  162    h_flex, prelude::*, ButtonSize, ButtonStyle, Disclosure, IconButton, IconName, IconSize,
  163    ListItem, Popover, PopoverMenuHandle, Tooltip,
  164};
  165use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  166use workspace::item::{ItemHandle, PreviewTabsSettings};
  167use workspace::notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt};
  168use workspace::{
  169    searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
  170};
  171use workspace::{Item as WorkspaceItem, OpenInTerminal, OpenTerminal, TabBarSettings, Toast};
  172
  173use crate::hover_links::find_url;
  174use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  175
  176pub const FILE_HEADER_HEIGHT: u32 = 2;
  177pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  178pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
  179pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  180const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  181const MAX_LINE_LEN: usize = 1024;
  182const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  183const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  184pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  185#[doc(hidden)]
  186pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  187#[doc(hidden)]
  188pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  189
  190pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
  191pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  192
  193pub fn render_parsed_markdown(
  194    element_id: impl Into<ElementId>,
  195    parsed: &language::ParsedMarkdown,
  196    editor_style: &EditorStyle,
  197    workspace: Option<WeakView<Workspace>>,
  198    cx: &mut WindowContext,
  199) -> InteractiveText {
  200    let code_span_background_color = cx
  201        .theme()
  202        .colors()
  203        .editor_document_highlight_read_background;
  204
  205    let highlights = gpui::combine_highlights(
  206        parsed.highlights.iter().filter_map(|(range, highlight)| {
  207            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
  208            Some((range.clone(), highlight))
  209        }),
  210        parsed
  211            .regions
  212            .iter()
  213            .zip(&parsed.region_ranges)
  214            .filter_map(|(region, range)| {
  215                if region.code {
  216                    Some((
  217                        range.clone(),
  218                        HighlightStyle {
  219                            background_color: Some(code_span_background_color),
  220                            ..Default::default()
  221                        },
  222                    ))
  223                } else {
  224                    None
  225                }
  226            }),
  227    );
  228
  229    let mut links = Vec::new();
  230    let mut link_ranges = Vec::new();
  231    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
  232        if let Some(link) = region.link.clone() {
  233            links.push(link);
  234            link_ranges.push(range.clone());
  235        }
  236    }
  237
  238    InteractiveText::new(
  239        element_id,
  240        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
  241    )
  242    .on_click(link_ranges, move |clicked_range_ix, cx| {
  243        match &links[clicked_range_ix] {
  244            markdown::Link::Web { url } => cx.open_url(url),
  245            markdown::Link::Path { path } => {
  246                if let Some(workspace) = &workspace {
  247                    _ = workspace.update(cx, |workspace, cx| {
  248                        workspace.open_abs_path(path.clone(), false, cx).detach();
  249                    });
  250                }
  251            }
  252        }
  253    })
  254}
  255
  256#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  257pub(crate) enum InlayId {
  258    Suggestion(usize),
  259    Hint(usize),
  260}
  261
  262impl InlayId {
  263    fn id(&self) -> usize {
  264        match self {
  265            Self::Suggestion(id) => *id,
  266            Self::Hint(id) => *id,
  267        }
  268    }
  269}
  270
  271enum DiffRowHighlight {}
  272enum DocumentHighlightRead {}
  273enum DocumentHighlightWrite {}
  274enum InputComposition {}
  275
  276#[derive(Copy, Clone, PartialEq, Eq)]
  277pub enum Direction {
  278    Prev,
  279    Next,
  280}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes {
  291            Navigated::Yes
  292        } else {
  293            Navigated::No
  294        }
  295    }
  296}
  297
  298pub fn init_settings(cx: &mut AppContext) {
  299    EditorSettings::register(cx);
  300}
  301
  302pub fn init(cx: &mut AppContext) {
  303    init_settings(cx);
  304
  305    workspace::register_project_item::<Editor>(cx);
  306    workspace::FollowableViewRegistry::register::<Editor>(cx);
  307    workspace::register_serializable_item::<Editor>(cx);
  308
  309    cx.observe_new_views(
  310        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  311            workspace.register_action(Editor::new_file);
  312            workspace.register_action(Editor::new_file_vertical);
  313            workspace.register_action(Editor::new_file_horizontal);
  314        },
  315    )
  316    .detach();
  317
  318    cx.on_action(move |_: &workspace::NewFile, cx| {
  319        let app_state = workspace::AppState::global(cx);
  320        if let Some(app_state) = app_state.upgrade() {
  321            workspace::open_new(Default::default(), app_state, cx, |workspace, cx| {
  322                Editor::new_file(workspace, &Default::default(), cx)
  323            })
  324            .detach();
  325        }
  326    });
  327    cx.on_action(move |_: &workspace::NewWindow, cx| {
  328        let app_state = workspace::AppState::global(cx);
  329        if let Some(app_state) = app_state.upgrade() {
  330            workspace::open_new(Default::default(), app_state, cx, |workspace, cx| {
  331                Editor::new_file(workspace, &Default::default(), cx)
  332            })
  333            .detach();
  334        }
  335    });
  336}
  337
  338pub struct SearchWithinRange;
  339
  340trait InvalidationRegion {
  341    fn ranges(&self) -> &[Range<Anchor>];
  342}
  343
  344#[derive(Clone, Debug, PartialEq)]
  345pub enum SelectPhase {
  346    Begin {
  347        position: DisplayPoint,
  348        add: bool,
  349        click_count: usize,
  350    },
  351    BeginColumnar {
  352        position: DisplayPoint,
  353        reset: bool,
  354        goal_column: u32,
  355    },
  356    Extend {
  357        position: DisplayPoint,
  358        click_count: usize,
  359    },
  360    Update {
  361        position: DisplayPoint,
  362        goal_column: u32,
  363        scroll_delta: gpui::Point<f32>,
  364    },
  365    End,
  366}
  367
  368#[derive(Clone, Debug)]
  369pub enum SelectMode {
  370    Character,
  371    Word(Range<Anchor>),
  372    Line(Range<Anchor>),
  373    All,
  374}
  375
  376#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  377pub enum EditorMode {
  378    SingleLine { auto_width: bool },
  379    AutoHeight { max_lines: usize },
  380    Full,
  381}
  382
  383#[derive(Copy, Clone, Debug)]
  384pub enum SoftWrap {
  385    /// Prefer not to wrap at all.
  386    ///
  387    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  388    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  389    GitDiff,
  390    /// Prefer a single line generally, unless an overly long line is encountered.
  391    None,
  392    /// Soft wrap lines that exceed the editor width.
  393    EditorWidth,
  394    /// Soft wrap lines at the preferred line length.
  395    Column(u32),
  396    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  397    Bounded(u32),
  398}
  399
  400#[derive(Clone)]
  401pub struct EditorStyle {
  402    pub background: Hsla,
  403    pub local_player: PlayerColor,
  404    pub text: TextStyle,
  405    pub scrollbar_width: Pixels,
  406    pub syntax: Arc<SyntaxTheme>,
  407    pub status: StatusColors,
  408    pub inlay_hints_style: HighlightStyle,
  409    pub suggestions_style: HighlightStyle,
  410    pub unnecessary_code_fade: f32,
  411}
  412
  413impl Default for EditorStyle {
  414    fn default() -> Self {
  415        Self {
  416            background: Hsla::default(),
  417            local_player: PlayerColor::default(),
  418            text: TextStyle::default(),
  419            scrollbar_width: Pixels::default(),
  420            syntax: Default::default(),
  421            // HACK: Status colors don't have a real default.
  422            // We should look into removing the status colors from the editor
  423            // style and retrieve them directly from the theme.
  424            status: StatusColors::dark(),
  425            inlay_hints_style: HighlightStyle::default(),
  426            suggestions_style: HighlightStyle::default(),
  427            unnecessary_code_fade: Default::default(),
  428        }
  429    }
  430}
  431
  432pub fn make_inlay_hints_style(cx: &WindowContext) -> HighlightStyle {
  433    let show_background = language_settings::language_settings(None, None, cx)
  434        .inlay_hints
  435        .show_background;
  436
  437    HighlightStyle {
  438        color: Some(cx.theme().status().hint),
  439        background_color: show_background.then(|| cx.theme().status().hint_background),
  440        ..HighlightStyle::default()
  441    }
  442}
  443
  444type CompletionId = usize;
  445
  446#[derive(Clone, Debug)]
  447struct CompletionState {
  448    // render_inlay_ids represents the inlay hints that are inserted
  449    // for rendering the inline completions. They may be discontinuous
  450    // in the event that the completion provider returns some intersection
  451    // with the existing content.
  452    render_inlay_ids: Vec<InlayId>,
  453    // text is the resulting rope that is inserted when the user accepts a completion.
  454    text: Rope,
  455    // position is the position of the cursor when the completion was triggered.
  456    position: multi_buffer::Anchor,
  457    // delete_range is the range of text that this completion state covers.
  458    // if the completion is accepted, this range should be deleted.
  459    delete_range: Option<Range<multi_buffer::Anchor>>,
  460}
  461
  462#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  463struct EditorActionId(usize);
  464
  465impl EditorActionId {
  466    pub fn post_inc(&mut self) -> Self {
  467        let answer = self.0;
  468
  469        *self = Self(answer + 1);
  470
  471        Self(answer)
  472    }
  473}
  474
  475// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  476// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  477
  478type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  479type GutterHighlight = (fn(&AppContext) -> Hsla, Arc<[Range<Anchor>]>);
  480
  481#[derive(Default)]
  482struct ScrollbarMarkerState {
  483    scrollbar_size: Size<Pixels>,
  484    dirty: bool,
  485    markers: Arc<[PaintQuad]>,
  486    pending_refresh: Option<Task<Result<()>>>,
  487}
  488
  489impl ScrollbarMarkerState {
  490    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  491        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  492    }
  493}
  494
  495#[derive(Clone, Debug)]
  496struct RunnableTasks {
  497    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  498    offset: MultiBufferOffset,
  499    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  500    column: u32,
  501    // Values of all named captures, including those starting with '_'
  502    extra_variables: HashMap<String, String>,
  503    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  504    context_range: Range<BufferOffset>,
  505}
  506
  507impl RunnableTasks {
  508    fn resolve<'a>(
  509        &'a self,
  510        cx: &'a task::TaskContext,
  511    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  512        self.templates.iter().filter_map(|(kind, template)| {
  513            template
  514                .resolve_task(&kind.to_id_base(), cx)
  515                .map(|task| (kind.clone(), task))
  516        })
  517    }
  518}
  519
  520#[derive(Clone)]
  521struct ResolvedTasks {
  522    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  523    position: Anchor,
  524}
  525#[derive(Copy, Clone, Debug)]
  526struct MultiBufferOffset(usize);
  527#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  528struct BufferOffset(usize);
  529
  530// Addons allow storing per-editor state in other crates (e.g. Vim)
  531pub trait Addon: 'static {
  532    fn extend_key_context(&self, _: &mut KeyContext, _: &AppContext) {}
  533
  534    fn to_any(&self) -> &dyn std::any::Any;
  535}
  536
  537/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
  538///
  539/// See the [module level documentation](self) for more information.
  540pub struct Editor {
  541    focus_handle: FocusHandle,
  542    last_focused_descendant: Option<WeakFocusHandle>,
  543    /// The text buffer being edited
  544    buffer: Model<MultiBuffer>,
  545    /// Map of how text in the buffer should be displayed.
  546    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  547    pub display_map: Model<DisplayMap>,
  548    pub selections: SelectionsCollection,
  549    pub scroll_manager: ScrollManager,
  550    /// When inline assist editors are linked, they all render cursors because
  551    /// typing enters text into each of them, even the ones that aren't focused.
  552    pub(crate) show_cursor_when_unfocused: bool,
  553    columnar_selection_tail: Option<Anchor>,
  554    add_selections_state: Option<AddSelectionsState>,
  555    select_next_state: Option<SelectNextState>,
  556    select_prev_state: Option<SelectNextState>,
  557    selection_history: SelectionHistory,
  558    autoclose_regions: Vec<AutocloseRegion>,
  559    snippet_stack: InvalidationStack<SnippetState>,
  560    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  561    ime_transaction: Option<TransactionId>,
  562    active_diagnostics: Option<ActiveDiagnosticGroup>,
  563    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  564
  565    project: Option<Model<Project>>,
  566    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  567    completion_provider: Option<Box<dyn CompletionProvider>>,
  568    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  569    blink_manager: Model<BlinkManager>,
  570    show_cursor_names: bool,
  571    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  572    pub show_local_selections: bool,
  573    mode: EditorMode,
  574    show_breadcrumbs: bool,
  575    show_gutter: bool,
  576    show_line_numbers: Option<bool>,
  577    use_relative_line_numbers: Option<bool>,
  578    show_git_diff_gutter: Option<bool>,
  579    show_code_actions: Option<bool>,
  580    show_runnables: Option<bool>,
  581    show_wrap_guides: Option<bool>,
  582    show_indent_guides: Option<bool>,
  583    placeholder_text: Option<Arc<str>>,
  584    highlight_order: usize,
  585    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  586    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  587    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  588    scrollbar_marker_state: ScrollbarMarkerState,
  589    active_indent_guides_state: ActiveIndentGuidesState,
  590    nav_history: Option<ItemNavHistory>,
  591    context_menu: RwLock<Option<ContextMenu>>,
  592    mouse_context_menu: Option<MouseContextMenu>,
  593    hunk_controls_menu_handle: PopoverMenuHandle<ui::ContextMenu>,
  594    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  595    signature_help_state: SignatureHelpState,
  596    auto_signature_help: Option<bool>,
  597    find_all_references_task_sources: Vec<Anchor>,
  598    next_completion_id: CompletionId,
  599    completion_documentation_pre_resolve_debounce: DebouncedDelay,
  600    available_code_actions: Option<(Location, Arc<[AvailableCodeAction]>)>,
  601    code_actions_task: Option<Task<Result<()>>>,
  602    document_highlights_task: Option<Task<()>>,
  603    linked_editing_range_task: Option<Task<Option<()>>>,
  604    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  605    pending_rename: Option<RenameState>,
  606    searchable: bool,
  607    cursor_shape: CursorShape,
  608    current_line_highlight: Option<CurrentLineHighlight>,
  609    collapse_matches: bool,
  610    autoindent_mode: Option<AutoindentMode>,
  611    workspace: Option<(WeakView<Workspace>, Option<WorkspaceId>)>,
  612    input_enabled: bool,
  613    use_modal_editing: bool,
  614    read_only: bool,
  615    leader_peer_id: Option<PeerId>,
  616    remote_id: Option<ViewId>,
  617    hover_state: HoverState,
  618    gutter_hovered: bool,
  619    hovered_link_state: Option<HoveredLinkState>,
  620    inline_completion_provider: Option<RegisteredInlineCompletionProvider>,
  621    code_action_providers: Vec<Arc<dyn CodeActionProvider>>,
  622    active_inline_completion: Option<CompletionState>,
  623    // enable_inline_completions is a switch that Vim can use to disable
  624    // inline completions based on its mode.
  625    enable_inline_completions: bool,
  626    show_inline_completions_override: Option<bool>,
  627    inlay_hint_cache: InlayHintCache,
  628    expanded_hunks: ExpandedHunks,
  629    next_inlay_id: usize,
  630    _subscriptions: Vec<Subscription>,
  631    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  632    gutter_dimensions: GutterDimensions,
  633    style: Option<EditorStyle>,
  634    text_style_refinement: Option<TextStyleRefinement>,
  635    next_editor_action_id: EditorActionId,
  636    editor_actions: Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut ViewContext<Self>)>>>>,
  637    use_autoclose: bool,
  638    use_auto_surround: bool,
  639    auto_replace_emoji_shortcode: bool,
  640    show_git_blame_gutter: bool,
  641    show_git_blame_inline: bool,
  642    show_git_blame_inline_delay_task: Option<Task<()>>,
  643    git_blame_inline_enabled: bool,
  644    serialize_dirty_buffers: bool,
  645    show_selection_menu: Option<bool>,
  646    blame: Option<Model<GitBlame>>,
  647    blame_subscription: Option<Subscription>,
  648    custom_context_menu: Option<
  649        Box<
  650            dyn 'static
  651                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
  652        >,
  653    >,
  654    last_bounds: Option<Bounds<Pixels>>,
  655    expect_bounds_change: Option<Bounds<Pixels>>,
  656    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  657    tasks_update_task: Option<Task<()>>,
  658    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  659    breadcrumb_header: Option<String>,
  660    focused_block: Option<FocusedBlock>,
  661    next_scroll_position: NextScrollCursorCenterTopBottom,
  662    addons: HashMap<TypeId, Box<dyn Addon>>,
  663    _scroll_cursor_center_top_bottom_task: Task<()>,
  664}
  665
  666#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  667enum NextScrollCursorCenterTopBottom {
  668    #[default]
  669    Center,
  670    Top,
  671    Bottom,
  672}
  673
  674impl NextScrollCursorCenterTopBottom {
  675    fn next(&self) -> Self {
  676        match self {
  677            Self::Center => Self::Top,
  678            Self::Top => Self::Bottom,
  679            Self::Bottom => Self::Center,
  680        }
  681    }
  682}
  683
  684#[derive(Clone)]
  685pub struct EditorSnapshot {
  686    pub mode: EditorMode,
  687    show_gutter: bool,
  688    show_line_numbers: Option<bool>,
  689    show_git_diff_gutter: Option<bool>,
  690    show_code_actions: Option<bool>,
  691    show_runnables: Option<bool>,
  692    git_blame_gutter_max_author_length: Option<usize>,
  693    pub display_snapshot: DisplaySnapshot,
  694    pub placeholder_text: Option<Arc<str>>,
  695    is_focused: bool,
  696    scroll_anchor: ScrollAnchor,
  697    ongoing_scroll: OngoingScroll,
  698    current_line_highlight: CurrentLineHighlight,
  699    gutter_hovered: bool,
  700}
  701
  702const GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED: usize = 20;
  703
  704#[derive(Default, Debug, Clone, Copy)]
  705pub struct GutterDimensions {
  706    pub left_padding: Pixels,
  707    pub right_padding: Pixels,
  708    pub width: Pixels,
  709    pub margin: Pixels,
  710    pub git_blame_entries_width: Option<Pixels>,
  711}
  712
  713impl GutterDimensions {
  714    /// The full width of the space taken up by the gutter.
  715    pub fn full_width(&self) -> Pixels {
  716        self.margin + self.width
  717    }
  718
  719    /// The width of the space reserved for the fold indicators,
  720    /// use alongside 'justify_end' and `gutter_width` to
  721    /// right align content with the line numbers
  722    pub fn fold_area_width(&self) -> Pixels {
  723        self.margin + self.right_padding
  724    }
  725}
  726
  727#[derive(Debug)]
  728pub struct RemoteSelection {
  729    pub replica_id: ReplicaId,
  730    pub selection: Selection<Anchor>,
  731    pub cursor_shape: CursorShape,
  732    pub peer_id: PeerId,
  733    pub line_mode: bool,
  734    pub participant_index: Option<ParticipantIndex>,
  735    pub user_name: Option<SharedString>,
  736}
  737
  738#[derive(Clone, Debug)]
  739struct SelectionHistoryEntry {
  740    selections: Arc<[Selection<Anchor>]>,
  741    select_next_state: Option<SelectNextState>,
  742    select_prev_state: Option<SelectNextState>,
  743    add_selections_state: Option<AddSelectionsState>,
  744}
  745
  746enum SelectionHistoryMode {
  747    Normal,
  748    Undoing,
  749    Redoing,
  750}
  751
  752#[derive(Clone, PartialEq, Eq, Hash)]
  753struct HoveredCursor {
  754    replica_id: u16,
  755    selection_id: usize,
  756}
  757
  758impl Default for SelectionHistoryMode {
  759    fn default() -> Self {
  760        Self::Normal
  761    }
  762}
  763
  764#[derive(Default)]
  765struct SelectionHistory {
  766    #[allow(clippy::type_complexity)]
  767    selections_by_transaction:
  768        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  769    mode: SelectionHistoryMode,
  770    undo_stack: VecDeque<SelectionHistoryEntry>,
  771    redo_stack: VecDeque<SelectionHistoryEntry>,
  772}
  773
  774impl SelectionHistory {
  775    fn insert_transaction(
  776        &mut self,
  777        transaction_id: TransactionId,
  778        selections: Arc<[Selection<Anchor>]>,
  779    ) {
  780        self.selections_by_transaction
  781            .insert(transaction_id, (selections, None));
  782    }
  783
  784    #[allow(clippy::type_complexity)]
  785    fn transaction(
  786        &self,
  787        transaction_id: TransactionId,
  788    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  789        self.selections_by_transaction.get(&transaction_id)
  790    }
  791
  792    #[allow(clippy::type_complexity)]
  793    fn transaction_mut(
  794        &mut self,
  795        transaction_id: TransactionId,
  796    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  797        self.selections_by_transaction.get_mut(&transaction_id)
  798    }
  799
  800    fn push(&mut self, entry: SelectionHistoryEntry) {
  801        if !entry.selections.is_empty() {
  802            match self.mode {
  803                SelectionHistoryMode::Normal => {
  804                    self.push_undo(entry);
  805                    self.redo_stack.clear();
  806                }
  807                SelectionHistoryMode::Undoing => self.push_redo(entry),
  808                SelectionHistoryMode::Redoing => self.push_undo(entry),
  809            }
  810        }
  811    }
  812
  813    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  814        if self
  815            .undo_stack
  816            .back()
  817            .map_or(true, |e| e.selections != entry.selections)
  818        {
  819            self.undo_stack.push_back(entry);
  820            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  821                self.undo_stack.pop_front();
  822            }
  823        }
  824    }
  825
  826    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  827        if self
  828            .redo_stack
  829            .back()
  830            .map_or(true, |e| e.selections != entry.selections)
  831        {
  832            self.redo_stack.push_back(entry);
  833            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  834                self.redo_stack.pop_front();
  835            }
  836        }
  837    }
  838}
  839
  840struct RowHighlight {
  841    index: usize,
  842    range: Range<Anchor>,
  843    color: Hsla,
  844    should_autoscroll: bool,
  845}
  846
  847#[derive(Clone, Debug)]
  848struct AddSelectionsState {
  849    above: bool,
  850    stack: Vec<usize>,
  851}
  852
  853#[derive(Clone)]
  854struct SelectNextState {
  855    query: AhoCorasick,
  856    wordwise: bool,
  857    done: bool,
  858}
  859
  860impl std::fmt::Debug for SelectNextState {
  861    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  862        f.debug_struct(std::any::type_name::<Self>())
  863            .field("wordwise", &self.wordwise)
  864            .field("done", &self.done)
  865            .finish()
  866    }
  867}
  868
  869#[derive(Debug)]
  870struct AutocloseRegion {
  871    selection_id: usize,
  872    range: Range<Anchor>,
  873    pair: BracketPair,
  874}
  875
  876#[derive(Debug)]
  877struct SnippetState {
  878    ranges: Vec<Vec<Range<Anchor>>>,
  879    active_index: usize,
  880}
  881
  882#[doc(hidden)]
  883pub struct RenameState {
  884    pub range: Range<Anchor>,
  885    pub old_name: Arc<str>,
  886    pub editor: View<Editor>,
  887    block_id: CustomBlockId,
  888}
  889
  890struct InvalidationStack<T>(Vec<T>);
  891
  892struct RegisteredInlineCompletionProvider {
  893    provider: Arc<dyn InlineCompletionProviderHandle>,
  894    _subscription: Subscription,
  895}
  896
  897enum ContextMenu {
  898    Completions(CompletionsMenu),
  899    CodeActions(CodeActionsMenu),
  900}
  901
  902impl ContextMenu {
  903    fn select_first(
  904        &mut self,
  905        provider: Option<&dyn CompletionProvider>,
  906        cx: &mut ViewContext<Editor>,
  907    ) -> bool {
  908        if self.visible() {
  909            match self {
  910                ContextMenu::Completions(menu) => menu.select_first(provider, cx),
  911                ContextMenu::CodeActions(menu) => menu.select_first(cx),
  912            }
  913            true
  914        } else {
  915            false
  916        }
  917    }
  918
  919    fn select_prev(
  920        &mut self,
  921        provider: Option<&dyn CompletionProvider>,
  922        cx: &mut ViewContext<Editor>,
  923    ) -> bool {
  924        if self.visible() {
  925            match self {
  926                ContextMenu::Completions(menu) => menu.select_prev(provider, cx),
  927                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  928            }
  929            true
  930        } else {
  931            false
  932        }
  933    }
  934
  935    fn select_next(
  936        &mut self,
  937        provider: Option<&dyn CompletionProvider>,
  938        cx: &mut ViewContext<Editor>,
  939    ) -> bool {
  940        if self.visible() {
  941            match self {
  942                ContextMenu::Completions(menu) => menu.select_next(provider, cx),
  943                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  944            }
  945            true
  946        } else {
  947            false
  948        }
  949    }
  950
  951    fn select_last(
  952        &mut self,
  953        provider: Option<&dyn CompletionProvider>,
  954        cx: &mut ViewContext<Editor>,
  955    ) -> bool {
  956        if self.visible() {
  957            match self {
  958                ContextMenu::Completions(menu) => menu.select_last(provider, cx),
  959                ContextMenu::CodeActions(menu) => menu.select_last(cx),
  960            }
  961            true
  962        } else {
  963            false
  964        }
  965    }
  966
  967    fn visible(&self) -> bool {
  968        match self {
  969            ContextMenu::Completions(menu) => menu.visible(),
  970            ContextMenu::CodeActions(menu) => menu.visible(),
  971        }
  972    }
  973
  974    fn render(
  975        &self,
  976        cursor_position: DisplayPoint,
  977        style: &EditorStyle,
  978        max_height: Pixels,
  979        workspace: Option<WeakView<Workspace>>,
  980        cx: &mut ViewContext<Editor>,
  981    ) -> (ContextMenuOrigin, AnyElement) {
  982        match self {
  983            ContextMenu::Completions(menu) => (
  984                ContextMenuOrigin::EditorPoint(cursor_position),
  985                menu.render(style, max_height, workspace, cx),
  986            ),
  987            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
  988        }
  989    }
  990}
  991
  992enum ContextMenuOrigin {
  993    EditorPoint(DisplayPoint),
  994    GutterIndicator(DisplayRow),
  995}
  996
  997#[derive(Clone)]
  998struct CompletionsMenu {
  999    id: CompletionId,
 1000    sort_completions: bool,
 1001    initial_position: Anchor,
 1002    buffer: Model<Buffer>,
 1003    completions: Arc<RwLock<Box<[Completion]>>>,
 1004    match_candidates: Arc<[StringMatchCandidate]>,
 1005    matches: Arc<[StringMatch]>,
 1006    selected_item: usize,
 1007    scroll_handle: UniformListScrollHandle,
 1008    selected_completion_documentation_resolve_debounce: Arc<Mutex<DebouncedDelay>>,
 1009}
 1010
 1011impl CompletionsMenu {
 1012    fn select_first(
 1013        &mut self,
 1014        provider: Option<&dyn CompletionProvider>,
 1015        cx: &mut ViewContext<Editor>,
 1016    ) {
 1017        self.selected_item = 0;
 1018        self.scroll_handle
 1019            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1020        self.attempt_resolve_selected_completion_documentation(provider, cx);
 1021        cx.notify();
 1022    }
 1023
 1024    fn select_prev(
 1025        &mut self,
 1026        provider: Option<&dyn CompletionProvider>,
 1027        cx: &mut ViewContext<Editor>,
 1028    ) {
 1029        if self.selected_item > 0 {
 1030            self.selected_item -= 1;
 1031        } else {
 1032            self.selected_item = self.matches.len() - 1;
 1033        }
 1034        self.scroll_handle
 1035            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1036        self.attempt_resolve_selected_completion_documentation(provider, cx);
 1037        cx.notify();
 1038    }
 1039
 1040    fn select_next(
 1041        &mut self,
 1042        provider: Option<&dyn CompletionProvider>,
 1043        cx: &mut ViewContext<Editor>,
 1044    ) {
 1045        if self.selected_item + 1 < self.matches.len() {
 1046            self.selected_item += 1;
 1047        } else {
 1048            self.selected_item = 0;
 1049        }
 1050        self.scroll_handle
 1051            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1052        self.attempt_resolve_selected_completion_documentation(provider, cx);
 1053        cx.notify();
 1054    }
 1055
 1056    fn select_last(
 1057        &mut self,
 1058        provider: Option<&dyn CompletionProvider>,
 1059        cx: &mut ViewContext<Editor>,
 1060    ) {
 1061        self.selected_item = self.matches.len() - 1;
 1062        self.scroll_handle
 1063            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1064        self.attempt_resolve_selected_completion_documentation(provider, cx);
 1065        cx.notify();
 1066    }
 1067
 1068    fn pre_resolve_completion_documentation(
 1069        buffer: Model<Buffer>,
 1070        completions: Arc<RwLock<Box<[Completion]>>>,
 1071        matches: Arc<[StringMatch]>,
 1072        editor: &Editor,
 1073        cx: &mut ViewContext<Editor>,
 1074    ) -> Task<()> {
 1075        let settings = EditorSettings::get_global(cx);
 1076        if !settings.show_completion_documentation {
 1077            return Task::ready(());
 1078        }
 1079
 1080        let Some(provider) = editor.completion_provider.as_ref() else {
 1081            return Task::ready(());
 1082        };
 1083
 1084        let resolve_task = provider.resolve_completions(
 1085            buffer,
 1086            matches.iter().map(|m| m.candidate_id).collect(),
 1087            completions.clone(),
 1088            cx,
 1089        );
 1090
 1091        cx.spawn(move |this, mut cx| async move {
 1092            if let Some(true) = resolve_task.await.log_err() {
 1093                this.update(&mut cx, |_, cx| cx.notify()).ok();
 1094            }
 1095        })
 1096    }
 1097
 1098    fn attempt_resolve_selected_completion_documentation(
 1099        &mut self,
 1100        provider: Option<&dyn CompletionProvider>,
 1101        cx: &mut ViewContext<Editor>,
 1102    ) {
 1103        let settings = EditorSettings::get_global(cx);
 1104        if !settings.show_completion_documentation {
 1105            return;
 1106        }
 1107
 1108        let completion_index = self.matches[self.selected_item].candidate_id;
 1109        let Some(provider) = provider else {
 1110            return;
 1111        };
 1112
 1113        let resolve_task = provider.resolve_completions(
 1114            self.buffer.clone(),
 1115            vec![completion_index],
 1116            self.completions.clone(),
 1117            cx,
 1118        );
 1119
 1120        let delay_ms =
 1121            EditorSettings::get_global(cx).completion_documentation_secondary_query_debounce;
 1122        let delay = Duration::from_millis(delay_ms);
 1123
 1124        self.selected_completion_documentation_resolve_debounce
 1125            .lock()
 1126            .fire_new(delay, cx, |_, cx| {
 1127                cx.spawn(move |this, mut cx| async move {
 1128                    if let Some(true) = resolve_task.await.log_err() {
 1129                        this.update(&mut cx, |_, cx| cx.notify()).ok();
 1130                    }
 1131                })
 1132            });
 1133    }
 1134
 1135    fn visible(&self) -> bool {
 1136        !self.matches.is_empty()
 1137    }
 1138
 1139    fn render(
 1140        &self,
 1141        style: &EditorStyle,
 1142        max_height: Pixels,
 1143        workspace: Option<WeakView<Workspace>>,
 1144        cx: &mut ViewContext<Editor>,
 1145    ) -> AnyElement {
 1146        let settings = EditorSettings::get_global(cx);
 1147        let show_completion_documentation = settings.show_completion_documentation;
 1148
 1149        let widest_completion_ix = self
 1150            .matches
 1151            .iter()
 1152            .enumerate()
 1153            .max_by_key(|(_, mat)| {
 1154                let completions = self.completions.read();
 1155                let completion = &completions[mat.candidate_id];
 1156                let documentation = &completion.documentation;
 1157
 1158                let mut len = completion.label.text.chars().count();
 1159                if let Some(Documentation::SingleLine(text)) = documentation {
 1160                    if show_completion_documentation {
 1161                        len += text.chars().count();
 1162                    }
 1163                }
 1164
 1165                len
 1166            })
 1167            .map(|(ix, _)| ix);
 1168
 1169        let completions = self.completions.clone();
 1170        let matches = self.matches.clone();
 1171        let selected_item = self.selected_item;
 1172        let style = style.clone();
 1173
 1174        let multiline_docs = if show_completion_documentation {
 1175            let mat = &self.matches[selected_item];
 1176            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
 1177                Some(Documentation::MultiLinePlainText(text)) => {
 1178                    Some(div().child(SharedString::from(text.clone())))
 1179                }
 1180                Some(Documentation::MultiLineMarkdown(parsed)) if !parsed.text.is_empty() => {
 1181                    Some(div().child(render_parsed_markdown(
 1182                        "completions_markdown",
 1183                        parsed,
 1184                        &style,
 1185                        workspace,
 1186                        cx,
 1187                    )))
 1188                }
 1189                _ => None,
 1190            };
 1191            multiline_docs.map(|div| {
 1192                div.id("multiline_docs")
 1193                    .max_h(max_height)
 1194                    .flex_1()
 1195                    .px_1p5()
 1196                    .py_1()
 1197                    .min_w(px(260.))
 1198                    .max_w(px(640.))
 1199                    .w(px(500.))
 1200                    .overflow_y_scroll()
 1201                    .occlude()
 1202            })
 1203        } else {
 1204            None
 1205        };
 1206
 1207        let list = uniform_list(
 1208            cx.view().clone(),
 1209            "completions",
 1210            matches.len(),
 1211            move |_editor, range, cx| {
 1212                let start_ix = range.start;
 1213                let completions_guard = completions.read();
 1214
 1215                matches[range]
 1216                    .iter()
 1217                    .enumerate()
 1218                    .map(|(ix, mat)| {
 1219                        let item_ix = start_ix + ix;
 1220                        let candidate_id = mat.candidate_id;
 1221                        let completion = &completions_guard[candidate_id];
 1222
 1223                        let documentation = if show_completion_documentation {
 1224                            &completion.documentation
 1225                        } else {
 1226                            &None
 1227                        };
 1228
 1229                        let highlights = gpui::combine_highlights(
 1230                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
 1231                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
 1232                                |(range, mut highlight)| {
 1233                                    // Ignore font weight for syntax highlighting, as we'll use it
 1234                                    // for fuzzy matches.
 1235                                    highlight.font_weight = None;
 1236
 1237                                    if completion.lsp_completion.deprecated.unwrap_or(false) {
 1238                                        highlight.strikethrough = Some(StrikethroughStyle {
 1239                                            thickness: 1.0.into(),
 1240                                            ..Default::default()
 1241                                        });
 1242                                        highlight.color = Some(cx.theme().colors().text_muted);
 1243                                    }
 1244
 1245                                    (range, highlight)
 1246                                },
 1247                            ),
 1248                        );
 1249                        let completion_label = StyledText::new(completion.label.text.clone())
 1250                            .with_highlights(&style.text, highlights);
 1251                        let documentation_label =
 1252                            if let Some(Documentation::SingleLine(text)) = documentation {
 1253                                if text.trim().is_empty() {
 1254                                    None
 1255                                } else {
 1256                                    Some(
 1257                                        Label::new(text.clone())
 1258                                            .ml_4()
 1259                                            .size(LabelSize::Small)
 1260                                            .color(Color::Muted),
 1261                                    )
 1262                                }
 1263                            } else {
 1264                                None
 1265                            };
 1266
 1267                        let color_swatch = completion
 1268                            .color()
 1269                            .map(|color| div().size_4().bg(color).rounded_sm());
 1270
 1271                        div().min_w(px(220.)).max_w(px(540.)).child(
 1272                            ListItem::new(mat.candidate_id)
 1273                                .inset(true)
 1274                                .selected(item_ix == selected_item)
 1275                                .on_click(cx.listener(move |editor, _event, cx| {
 1276                                    cx.stop_propagation();
 1277                                    if let Some(task) = editor.confirm_completion(
 1278                                        &ConfirmCompletion {
 1279                                            item_ix: Some(item_ix),
 1280                                        },
 1281                                        cx,
 1282                                    ) {
 1283                                        task.detach_and_log_err(cx)
 1284                                    }
 1285                                }))
 1286                                .start_slot::<Div>(color_swatch)
 1287                                .child(h_flex().overflow_hidden().child(completion_label))
 1288                                .end_slot::<Label>(documentation_label),
 1289                        )
 1290                    })
 1291                    .collect()
 1292            },
 1293        )
 1294        .occlude()
 1295        .max_h(max_height)
 1296        .track_scroll(self.scroll_handle.clone())
 1297        .with_width_from_item(widest_completion_ix)
 1298        .with_sizing_behavior(ListSizingBehavior::Infer);
 1299
 1300        Popover::new()
 1301            .child(list)
 1302            .when_some(multiline_docs, |popover, multiline_docs| {
 1303                popover.aside(multiline_docs)
 1304            })
 1305            .into_any_element()
 1306    }
 1307
 1308    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
 1309        let mut matches = if let Some(query) = query {
 1310            fuzzy::match_strings(
 1311                &self.match_candidates,
 1312                query,
 1313                query.chars().any(|c| c.is_uppercase()),
 1314                100,
 1315                &Default::default(),
 1316                executor,
 1317            )
 1318            .await
 1319        } else {
 1320            self.match_candidates
 1321                .iter()
 1322                .enumerate()
 1323                .map(|(candidate_id, candidate)| StringMatch {
 1324                    candidate_id,
 1325                    score: Default::default(),
 1326                    positions: Default::default(),
 1327                    string: candidate.string.clone(),
 1328                })
 1329                .collect()
 1330        };
 1331
 1332        // Remove all candidates where the query's start does not match the start of any word in the candidate
 1333        if let Some(query) = query {
 1334            if let Some(query_start) = query.chars().next() {
 1335                matches.retain(|string_match| {
 1336                    split_words(&string_match.string).any(|word| {
 1337                        // Check that the first codepoint of the word as lowercase matches the first
 1338                        // codepoint of the query as lowercase
 1339                        word.chars()
 1340                            .flat_map(|codepoint| codepoint.to_lowercase())
 1341                            .zip(query_start.to_lowercase())
 1342                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 1343                    })
 1344                });
 1345            }
 1346        }
 1347
 1348        let completions = self.completions.read();
 1349        if self.sort_completions {
 1350            matches.sort_unstable_by_key(|mat| {
 1351                // We do want to strike a balance here between what the language server tells us
 1352                // to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
 1353                // `Creat` and there is a local variable called `CreateComponent`).
 1354                // So what we do is: we bucket all matches into two buckets
 1355                // - Strong matches
 1356                // - Weak matches
 1357                // Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
 1358                // and the Weak matches are the rest.
 1359                //
 1360                // For the strong matches, we sort by our fuzzy-finder score first and for the weak
 1361                // matches, we prefer language-server sort_text first.
 1362                //
 1363                // The thinking behind that: we want to show strong matches first in order of relevance(fuzzy score).
 1364                // Rest of the matches(weak) can be sorted as language-server expects.
 1365
 1366                #[derive(PartialEq, Eq, PartialOrd, Ord)]
 1367                enum MatchScore<'a> {
 1368                    Strong {
 1369                        score: Reverse<OrderedFloat<f64>>,
 1370                        sort_text: Option<&'a str>,
 1371                        sort_key: (usize, &'a str),
 1372                    },
 1373                    Weak {
 1374                        sort_text: Option<&'a str>,
 1375                        score: Reverse<OrderedFloat<f64>>,
 1376                        sort_key: (usize, &'a str),
 1377                    },
 1378                }
 1379
 1380                let completion = &completions[mat.candidate_id];
 1381                let sort_key = completion.sort_key();
 1382                let sort_text = completion.lsp_completion.sort_text.as_deref();
 1383                let score = Reverse(OrderedFloat(mat.score));
 1384
 1385                if mat.score >= 0.2 {
 1386                    MatchScore::Strong {
 1387                        score,
 1388                        sort_text,
 1389                        sort_key,
 1390                    }
 1391                } else {
 1392                    MatchScore::Weak {
 1393                        sort_text,
 1394                        score,
 1395                        sort_key,
 1396                    }
 1397                }
 1398            });
 1399        }
 1400
 1401        for mat in &mut matches {
 1402            let completion = &completions[mat.candidate_id];
 1403            mat.string.clone_from(&completion.label.text);
 1404            for position in &mut mat.positions {
 1405                *position += completion.label.filter_range.start;
 1406            }
 1407        }
 1408        drop(completions);
 1409
 1410        self.matches = matches.into();
 1411        self.selected_item = 0;
 1412    }
 1413}
 1414
 1415struct AvailableCodeAction {
 1416    excerpt_id: ExcerptId,
 1417    action: CodeAction,
 1418    provider: Arc<dyn CodeActionProvider>,
 1419}
 1420
 1421#[derive(Clone)]
 1422struct CodeActionContents {
 1423    tasks: Option<Arc<ResolvedTasks>>,
 1424    actions: Option<Arc<[AvailableCodeAction]>>,
 1425}
 1426
 1427impl CodeActionContents {
 1428    fn len(&self) -> usize {
 1429        match (&self.tasks, &self.actions) {
 1430            (Some(tasks), Some(actions)) => actions.len() + tasks.templates.len(),
 1431            (Some(tasks), None) => tasks.templates.len(),
 1432            (None, Some(actions)) => actions.len(),
 1433            (None, None) => 0,
 1434        }
 1435    }
 1436
 1437    fn is_empty(&self) -> bool {
 1438        match (&self.tasks, &self.actions) {
 1439            (Some(tasks), Some(actions)) => actions.is_empty() && tasks.templates.is_empty(),
 1440            (Some(tasks), None) => tasks.templates.is_empty(),
 1441            (None, Some(actions)) => actions.is_empty(),
 1442            (None, None) => true,
 1443        }
 1444    }
 1445
 1446    fn iter(&self) -> impl Iterator<Item = CodeActionsItem> + '_ {
 1447        self.tasks
 1448            .iter()
 1449            .flat_map(|tasks| {
 1450                tasks
 1451                    .templates
 1452                    .iter()
 1453                    .map(|(kind, task)| CodeActionsItem::Task(kind.clone(), task.clone()))
 1454            })
 1455            .chain(self.actions.iter().flat_map(|actions| {
 1456                actions.iter().map(|available| CodeActionsItem::CodeAction {
 1457                    excerpt_id: available.excerpt_id,
 1458                    action: available.action.clone(),
 1459                    provider: available.provider.clone(),
 1460                })
 1461            }))
 1462    }
 1463    fn get(&self, index: usize) -> Option<CodeActionsItem> {
 1464        match (&self.tasks, &self.actions) {
 1465            (Some(tasks), Some(actions)) => {
 1466                if index < tasks.templates.len() {
 1467                    tasks
 1468                        .templates
 1469                        .get(index)
 1470                        .cloned()
 1471                        .map(|(kind, task)| CodeActionsItem::Task(kind, task))
 1472                } else {
 1473                    actions.get(index - tasks.templates.len()).map(|available| {
 1474                        CodeActionsItem::CodeAction {
 1475                            excerpt_id: available.excerpt_id,
 1476                            action: available.action.clone(),
 1477                            provider: available.provider.clone(),
 1478                        }
 1479                    })
 1480                }
 1481            }
 1482            (Some(tasks), None) => tasks
 1483                .templates
 1484                .get(index)
 1485                .cloned()
 1486                .map(|(kind, task)| CodeActionsItem::Task(kind, task)),
 1487            (None, Some(actions)) => {
 1488                actions
 1489                    .get(index)
 1490                    .map(|available| CodeActionsItem::CodeAction {
 1491                        excerpt_id: available.excerpt_id,
 1492                        action: available.action.clone(),
 1493                        provider: available.provider.clone(),
 1494                    })
 1495            }
 1496            (None, None) => None,
 1497        }
 1498    }
 1499}
 1500
 1501#[allow(clippy::large_enum_variant)]
 1502#[derive(Clone)]
 1503enum CodeActionsItem {
 1504    Task(TaskSourceKind, ResolvedTask),
 1505    CodeAction {
 1506        excerpt_id: ExcerptId,
 1507        action: CodeAction,
 1508        provider: Arc<dyn CodeActionProvider>,
 1509    },
 1510}
 1511
 1512impl CodeActionsItem {
 1513    fn as_task(&self) -> Option<&ResolvedTask> {
 1514        let Self::Task(_, task) = self else {
 1515            return None;
 1516        };
 1517        Some(task)
 1518    }
 1519    fn as_code_action(&self) -> Option<&CodeAction> {
 1520        let Self::CodeAction { action, .. } = self else {
 1521            return None;
 1522        };
 1523        Some(action)
 1524    }
 1525    fn label(&self) -> String {
 1526        match self {
 1527            Self::CodeAction { action, .. } => action.lsp_action.title.clone(),
 1528            Self::Task(_, task) => task.resolved_label.clone(),
 1529        }
 1530    }
 1531}
 1532
 1533struct CodeActionsMenu {
 1534    actions: CodeActionContents,
 1535    buffer: Model<Buffer>,
 1536    selected_item: usize,
 1537    scroll_handle: UniformListScrollHandle,
 1538    deployed_from_indicator: Option<DisplayRow>,
 1539}
 1540
 1541impl CodeActionsMenu {
 1542    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
 1543        self.selected_item = 0;
 1544        self.scroll_handle
 1545            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1546        cx.notify()
 1547    }
 1548
 1549    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 1550        if self.selected_item > 0 {
 1551            self.selected_item -= 1;
 1552        } else {
 1553            self.selected_item = self.actions.len() - 1;
 1554        }
 1555        self.scroll_handle
 1556            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1557        cx.notify();
 1558    }
 1559
 1560    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 1561        if self.selected_item + 1 < self.actions.len() {
 1562            self.selected_item += 1;
 1563        } else {
 1564            self.selected_item = 0;
 1565        }
 1566        self.scroll_handle
 1567            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1568        cx.notify();
 1569    }
 1570
 1571    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
 1572        self.selected_item = self.actions.len() - 1;
 1573        self.scroll_handle
 1574            .scroll_to_item(self.selected_item, ScrollStrategy::Top);
 1575        cx.notify()
 1576    }
 1577
 1578    fn visible(&self) -> bool {
 1579        !self.actions.is_empty()
 1580    }
 1581
 1582    fn render(
 1583        &self,
 1584        cursor_position: DisplayPoint,
 1585        _style: &EditorStyle,
 1586        max_height: Pixels,
 1587        cx: &mut ViewContext<Editor>,
 1588    ) -> (ContextMenuOrigin, AnyElement) {
 1589        let actions = self.actions.clone();
 1590        let selected_item = self.selected_item;
 1591        let element = uniform_list(
 1592            cx.view().clone(),
 1593            "code_actions_menu",
 1594            self.actions.len(),
 1595            move |_this, range, cx| {
 1596                actions
 1597                    .iter()
 1598                    .skip(range.start)
 1599                    .take(range.end - range.start)
 1600                    .enumerate()
 1601                    .map(|(ix, action)| {
 1602                        let item_ix = range.start + ix;
 1603                        let selected = selected_item == item_ix;
 1604                        let colors = cx.theme().colors();
 1605                        div()
 1606                            .px_1()
 1607                            .rounded_md()
 1608                            .text_color(colors.text)
 1609                            .when(selected, |style| {
 1610                                style
 1611                                    .bg(colors.element_active)
 1612                                    .text_color(colors.text_accent)
 1613                            })
 1614                            .hover(|style| {
 1615                                style
 1616                                    .bg(colors.element_hover)
 1617                                    .text_color(colors.text_accent)
 1618                            })
 1619                            .whitespace_nowrap()
 1620                            .when_some(action.as_code_action(), |this, action| {
 1621                                this.on_mouse_down(
 1622                                    MouseButton::Left,
 1623                                    cx.listener(move |editor, _, cx| {
 1624                                        cx.stop_propagation();
 1625                                        if let Some(task) = editor.confirm_code_action(
 1626                                            &ConfirmCodeAction {
 1627                                                item_ix: Some(item_ix),
 1628                                            },
 1629                                            cx,
 1630                                        ) {
 1631                                            task.detach_and_log_err(cx)
 1632                                        }
 1633                                    }),
 1634                                )
 1635                                // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
 1636                                .child(SharedString::from(action.lsp_action.title.clone()))
 1637                            })
 1638                            .when_some(action.as_task(), |this, task| {
 1639                                this.on_mouse_down(
 1640                                    MouseButton::Left,
 1641                                    cx.listener(move |editor, _, cx| {
 1642                                        cx.stop_propagation();
 1643                                        if let Some(task) = editor.confirm_code_action(
 1644                                            &ConfirmCodeAction {
 1645                                                item_ix: Some(item_ix),
 1646                                            },
 1647                                            cx,
 1648                                        ) {
 1649                                            task.detach_and_log_err(cx)
 1650                                        }
 1651                                    }),
 1652                                )
 1653                                .child(SharedString::from(task.resolved_label.clone()))
 1654                            })
 1655                    })
 1656                    .collect()
 1657            },
 1658        )
 1659        .elevation_1(cx)
 1660        .p_1()
 1661        .max_h(max_height)
 1662        .occlude()
 1663        .track_scroll(self.scroll_handle.clone())
 1664        .with_width_from_item(
 1665            self.actions
 1666                .iter()
 1667                .enumerate()
 1668                .max_by_key(|(_, action)| match action {
 1669                    CodeActionsItem::Task(_, task) => task.resolved_label.chars().count(),
 1670                    CodeActionsItem::CodeAction { action, .. } => {
 1671                        action.lsp_action.title.chars().count()
 1672                    }
 1673                })
 1674                .map(|(ix, _)| ix),
 1675        )
 1676        .with_sizing_behavior(ListSizingBehavior::Infer)
 1677        .into_any_element();
 1678
 1679        let cursor_position = if let Some(row) = self.deployed_from_indicator {
 1680            ContextMenuOrigin::GutterIndicator(row)
 1681        } else {
 1682            ContextMenuOrigin::EditorPoint(cursor_position)
 1683        };
 1684
 1685        (cursor_position, element)
 1686    }
 1687}
 1688
 1689#[derive(Debug)]
 1690struct ActiveDiagnosticGroup {
 1691    primary_range: Range<Anchor>,
 1692    primary_message: String,
 1693    group_id: usize,
 1694    blocks: HashMap<CustomBlockId, Diagnostic>,
 1695    is_valid: bool,
 1696}
 1697
 1698#[derive(Serialize, Deserialize, Clone, Debug)]
 1699pub struct ClipboardSelection {
 1700    pub len: usize,
 1701    pub is_entire_line: bool,
 1702    pub first_line_indent: u32,
 1703}
 1704
 1705#[derive(Debug)]
 1706pub(crate) struct NavigationData {
 1707    cursor_anchor: Anchor,
 1708    cursor_position: Point,
 1709    scroll_anchor: ScrollAnchor,
 1710    scroll_top_row: u32,
 1711}
 1712
 1713#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1714pub enum GotoDefinitionKind {
 1715    Symbol,
 1716    Declaration,
 1717    Type,
 1718    Implementation,
 1719}
 1720
 1721#[derive(Debug, Clone)]
 1722enum InlayHintRefreshReason {
 1723    Toggle(bool),
 1724    SettingsChange(InlayHintSettings),
 1725    NewLinesShown,
 1726    BufferEdited(HashSet<Arc<Language>>),
 1727    RefreshRequested,
 1728    ExcerptsRemoved(Vec<ExcerptId>),
 1729}
 1730
 1731impl InlayHintRefreshReason {
 1732    fn description(&self) -> &'static str {
 1733        match self {
 1734            Self::Toggle(_) => "toggle",
 1735            Self::SettingsChange(_) => "settings change",
 1736            Self::NewLinesShown => "new lines shown",
 1737            Self::BufferEdited(_) => "buffer edited",
 1738            Self::RefreshRequested => "refresh requested",
 1739            Self::ExcerptsRemoved(_) => "excerpts removed",
 1740        }
 1741    }
 1742}
 1743
 1744pub(crate) struct FocusedBlock {
 1745    id: BlockId,
 1746    focus_handle: WeakFocusHandle,
 1747}
 1748
 1749#[derive(Clone)]
 1750struct JumpData {
 1751    excerpt_id: ExcerptId,
 1752    position: Point,
 1753    anchor: text::Anchor,
 1754    path: Option<project::ProjectPath>,
 1755    line_offset_from_top: u32,
 1756}
 1757
 1758impl Editor {
 1759    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
 1760        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1761        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1762        Self::new(
 1763            EditorMode::SingleLine { auto_width: false },
 1764            buffer,
 1765            None,
 1766            false,
 1767            cx,
 1768        )
 1769    }
 1770
 1771    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
 1772        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1773        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1774        Self::new(EditorMode::Full, buffer, None, false, cx)
 1775    }
 1776
 1777    pub fn auto_width(cx: &mut ViewContext<Self>) -> Self {
 1778        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1779        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1780        Self::new(
 1781            EditorMode::SingleLine { auto_width: true },
 1782            buffer,
 1783            None,
 1784            false,
 1785            cx,
 1786        )
 1787    }
 1788
 1789    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
 1790        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1791        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1792        Self::new(
 1793            EditorMode::AutoHeight { max_lines },
 1794            buffer,
 1795            None,
 1796            false,
 1797            cx,
 1798        )
 1799    }
 1800
 1801    pub fn for_buffer(
 1802        buffer: Model<Buffer>,
 1803        project: Option<Model<Project>>,
 1804        cx: &mut ViewContext<Self>,
 1805    ) -> Self {
 1806        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1807        Self::new(EditorMode::Full, buffer, project, false, cx)
 1808    }
 1809
 1810    pub fn for_multibuffer(
 1811        buffer: Model<MultiBuffer>,
 1812        project: Option<Model<Project>>,
 1813        show_excerpt_controls: bool,
 1814        cx: &mut ViewContext<Self>,
 1815    ) -> Self {
 1816        Self::new(EditorMode::Full, buffer, project, show_excerpt_controls, cx)
 1817    }
 1818
 1819    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 1820        let show_excerpt_controls = self.display_map.read(cx).show_excerpt_controls();
 1821        let mut clone = Self::new(
 1822            self.mode,
 1823            self.buffer.clone(),
 1824            self.project.clone(),
 1825            show_excerpt_controls,
 1826            cx,
 1827        );
 1828        self.display_map.update(cx, |display_map, cx| {
 1829            let snapshot = display_map.snapshot(cx);
 1830            clone.display_map.update(cx, |display_map, cx| {
 1831                display_map.set_state(&snapshot, cx);
 1832            });
 1833        });
 1834        clone.selections.clone_state(&self.selections);
 1835        clone.scroll_manager.clone_state(&self.scroll_manager);
 1836        clone.searchable = self.searchable;
 1837        clone
 1838    }
 1839
 1840    pub fn new(
 1841        mode: EditorMode,
 1842        buffer: Model<MultiBuffer>,
 1843        project: Option<Model<Project>>,
 1844        show_excerpt_controls: bool,
 1845        cx: &mut ViewContext<Self>,
 1846    ) -> Self {
 1847        let style = cx.text_style();
 1848        let font_size = style.font_size.to_pixels(cx.rem_size());
 1849        let editor = cx.view().downgrade();
 1850        let fold_placeholder = FoldPlaceholder {
 1851            constrain_width: true,
 1852            render: Arc::new(move |fold_id, fold_range, cx| {
 1853                let editor = editor.clone();
 1854                div()
 1855                    .id(fold_id)
 1856                    .bg(cx.theme().colors().ghost_element_background)
 1857                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1858                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1859                    .rounded_sm()
 1860                    .size_full()
 1861                    .cursor_pointer()
 1862                    .child("")
 1863                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 1864                    .on_click(move |_, cx| {
 1865                        editor
 1866                            .update(cx, |editor, cx| {
 1867                                editor.unfold_ranges(
 1868                                    &[fold_range.start..fold_range.end],
 1869                                    true,
 1870                                    false,
 1871                                    cx,
 1872                                );
 1873                                cx.stop_propagation();
 1874                            })
 1875                            .ok();
 1876                    })
 1877                    .into_any()
 1878            }),
 1879            merge_adjacent: true,
 1880            ..Default::default()
 1881        };
 1882        let display_map = cx.new_model(|cx| {
 1883            DisplayMap::new(
 1884                buffer.clone(),
 1885                style.font(),
 1886                font_size,
 1887                None,
 1888                show_excerpt_controls,
 1889                FILE_HEADER_HEIGHT,
 1890                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1891                MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT,
 1892                fold_placeholder,
 1893                cx,
 1894            )
 1895        });
 1896
 1897        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1898
 1899        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1900
 1901        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1902            .then(|| language_settings::SoftWrap::None);
 1903
 1904        let mut project_subscriptions = Vec::new();
 1905        if mode == EditorMode::Full {
 1906            if let Some(project) = project.as_ref() {
 1907                if buffer.read(cx).is_singleton() {
 1908                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
 1909                        cx.emit(EditorEvent::TitleChanged);
 1910                    }));
 1911                }
 1912                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
 1913                    if let project::Event::RefreshInlayHints = event {
 1914                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1915                    } else if let project::Event::SnippetEdit(id, snippet_edits) = event {
 1916                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1917                            let focus_handle = editor.focus_handle(cx);
 1918                            if focus_handle.is_focused(cx) {
 1919                                let snapshot = buffer.read(cx).snapshot();
 1920                                for (range, snippet) in snippet_edits {
 1921                                    let editor_range =
 1922                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1923                                    editor
 1924                                        .insert_snippet(&[editor_range], snippet.clone(), cx)
 1925                                        .ok();
 1926                                }
 1927                            }
 1928                        }
 1929                    }
 1930                }));
 1931                if let Some(task_inventory) = project
 1932                    .read(cx)
 1933                    .task_store()
 1934                    .read(cx)
 1935                    .task_inventory()
 1936                    .cloned()
 1937                {
 1938                    project_subscriptions.push(cx.observe(&task_inventory, |editor, _, cx| {
 1939                        editor.tasks_update_task = Some(editor.refresh_runnables(cx));
 1940                    }));
 1941                }
 1942            }
 1943        }
 1944
 1945        let inlay_hint_settings = inlay_hint_settings(
 1946            selections.newest_anchor().head(),
 1947            &buffer.read(cx).snapshot(cx),
 1948            cx,
 1949        );
 1950        let focus_handle = cx.focus_handle();
 1951        cx.on_focus(&focus_handle, Self::handle_focus).detach();
 1952        cx.on_focus_in(&focus_handle, Self::handle_focus_in)
 1953            .detach();
 1954        cx.on_focus_out(&focus_handle, Self::handle_focus_out)
 1955            .detach();
 1956        cx.on_blur(&focus_handle, Self::handle_blur).detach();
 1957
 1958        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1959            Some(false)
 1960        } else {
 1961            None
 1962        };
 1963
 1964        let mut code_action_providers = Vec::new();
 1965        if let Some(project) = project.clone() {
 1966            code_action_providers.push(Arc::new(project) as Arc<_>);
 1967        }
 1968
 1969        let mut this = Self {
 1970            focus_handle,
 1971            show_cursor_when_unfocused: false,
 1972            last_focused_descendant: None,
 1973            buffer: buffer.clone(),
 1974            display_map: display_map.clone(),
 1975            selections,
 1976            scroll_manager: ScrollManager::new(cx),
 1977            columnar_selection_tail: None,
 1978            add_selections_state: None,
 1979            select_next_state: None,
 1980            select_prev_state: None,
 1981            selection_history: Default::default(),
 1982            autoclose_regions: Default::default(),
 1983            snippet_stack: Default::default(),
 1984            select_larger_syntax_node_stack: Vec::new(),
 1985            ime_transaction: Default::default(),
 1986            active_diagnostics: None,
 1987            soft_wrap_mode_override,
 1988            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1989            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1990            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1991            project,
 1992            blink_manager: blink_manager.clone(),
 1993            show_local_selections: true,
 1994            mode,
 1995            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1996            show_gutter: mode == EditorMode::Full,
 1997            show_line_numbers: None,
 1998            use_relative_line_numbers: None,
 1999            show_git_diff_gutter: None,
 2000            show_code_actions: None,
 2001            show_runnables: None,
 2002            show_wrap_guides: None,
 2003            show_indent_guides,
 2004            placeholder_text: None,
 2005            highlight_order: 0,
 2006            highlighted_rows: HashMap::default(),
 2007            background_highlights: Default::default(),
 2008            gutter_highlights: TreeMap::default(),
 2009            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2010            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2011            nav_history: None,
 2012            context_menu: RwLock::new(None),
 2013            mouse_context_menu: None,
 2014            hunk_controls_menu_handle: PopoverMenuHandle::default(),
 2015            completion_tasks: Default::default(),
 2016            signature_help_state: SignatureHelpState::default(),
 2017            auto_signature_help: None,
 2018            find_all_references_task_sources: Vec::new(),
 2019            next_completion_id: 0,
 2020            completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
 2021            next_inlay_id: 0,
 2022            code_action_providers,
 2023            available_code_actions: Default::default(),
 2024            code_actions_task: Default::default(),
 2025            document_highlights_task: Default::default(),
 2026            linked_editing_range_task: Default::default(),
 2027            pending_rename: Default::default(),
 2028            searchable: true,
 2029            cursor_shape: EditorSettings::get_global(cx)
 2030                .cursor_shape
 2031                .unwrap_or_default(),
 2032            current_line_highlight: None,
 2033            autoindent_mode: Some(AutoindentMode::EachLine),
 2034            collapse_matches: false,
 2035            workspace: None,
 2036            input_enabled: true,
 2037            use_modal_editing: mode == EditorMode::Full,
 2038            read_only: false,
 2039            use_autoclose: true,
 2040            use_auto_surround: true,
 2041            auto_replace_emoji_shortcode: false,
 2042            leader_peer_id: None,
 2043            remote_id: None,
 2044            hover_state: Default::default(),
 2045            hovered_link_state: Default::default(),
 2046            inline_completion_provider: None,
 2047            active_inline_completion: None,
 2048            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2049            expanded_hunks: ExpandedHunks::default(),
 2050            gutter_hovered: false,
 2051            pixel_position_of_newest_cursor: None,
 2052            last_bounds: None,
 2053            expect_bounds_change: None,
 2054            gutter_dimensions: GutterDimensions::default(),
 2055            style: None,
 2056            show_cursor_names: false,
 2057            hovered_cursors: Default::default(),
 2058            next_editor_action_id: EditorActionId::default(),
 2059            editor_actions: Rc::default(),
 2060            show_inline_completions_override: None,
 2061            enable_inline_completions: true,
 2062            custom_context_menu: None,
 2063            show_git_blame_gutter: false,
 2064            show_git_blame_inline: false,
 2065            show_selection_menu: None,
 2066            show_git_blame_inline_delay_task: None,
 2067            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2068            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 2069                .session
 2070                .restore_unsaved_buffers,
 2071            blame: None,
 2072            blame_subscription: None,
 2073            tasks: Default::default(),
 2074            _subscriptions: vec![
 2075                cx.observe(&buffer, Self::on_buffer_changed),
 2076                cx.subscribe(&buffer, Self::on_buffer_event),
 2077                cx.observe(&display_map, Self::on_display_map_changed),
 2078                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2079                cx.observe_global::<SettingsStore>(Self::settings_changed),
 2080                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2081                cx.observe_window_activation(|editor, cx| {
 2082                    let active = cx.is_window_active();
 2083                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2084                        if active {
 2085                            blink_manager.enable(cx);
 2086                        } else {
 2087                            blink_manager.disable(cx);
 2088                        }
 2089                    });
 2090                }),
 2091            ],
 2092            tasks_update_task: None,
 2093            linked_edit_ranges: Default::default(),
 2094            previous_search_ranges: None,
 2095            breadcrumb_header: None,
 2096            focused_block: None,
 2097            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2098            addons: HashMap::default(),
 2099            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2100            text_style_refinement: None,
 2101        };
 2102        this.tasks_update_task = Some(this.refresh_runnables(cx));
 2103        this._subscriptions.extend(project_subscriptions);
 2104
 2105        this.end_selection(cx);
 2106        this.scroll_manager.show_scrollbar(cx);
 2107
 2108        if mode == EditorMode::Full {
 2109            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2110            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2111
 2112            if this.git_blame_inline_enabled {
 2113                this.git_blame_inline_enabled = true;
 2114                this.start_git_blame_inline(false, cx);
 2115            }
 2116        }
 2117
 2118        this.report_editor_event("open", None, cx);
 2119        this
 2120    }
 2121
 2122    pub fn mouse_menu_is_focused(&self, cx: &WindowContext) -> bool {
 2123        self.mouse_context_menu
 2124            .as_ref()
 2125            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(cx))
 2126    }
 2127
 2128    fn key_context(&self, cx: &ViewContext<Self>) -> KeyContext {
 2129        let mut key_context = KeyContext::new_with_defaults();
 2130        key_context.add("Editor");
 2131        let mode = match self.mode {
 2132            EditorMode::SingleLine { .. } => "single_line",
 2133            EditorMode::AutoHeight { .. } => "auto_height",
 2134            EditorMode::Full => "full",
 2135        };
 2136
 2137        if EditorSettings::jupyter_enabled(cx) {
 2138            key_context.add("jupyter");
 2139        }
 2140
 2141        key_context.set("mode", mode);
 2142        if self.pending_rename.is_some() {
 2143            key_context.add("renaming");
 2144        }
 2145        if self.context_menu_visible() {
 2146            match self.context_menu.read().as_ref() {
 2147                Some(ContextMenu::Completions(_)) => {
 2148                    key_context.add("menu");
 2149                    key_context.add("showing_completions")
 2150                }
 2151                Some(ContextMenu::CodeActions(_)) => {
 2152                    key_context.add("menu");
 2153                    key_context.add("showing_code_actions")
 2154                }
 2155                None => {}
 2156            }
 2157        }
 2158
 2159        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2160        if !self.focus_handle(cx).contains_focused(cx)
 2161            || (self.is_focused(cx) || self.mouse_menu_is_focused(cx))
 2162        {
 2163            for addon in self.addons.values() {
 2164                addon.extend_key_context(&mut key_context, cx)
 2165            }
 2166        }
 2167
 2168        if let Some(extension) = self
 2169            .buffer
 2170            .read(cx)
 2171            .as_singleton()
 2172            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 2173        {
 2174            key_context.set("extension", extension.to_string());
 2175        }
 2176
 2177        if self.has_active_inline_completion(cx) {
 2178            key_context.add("copilot_suggestion");
 2179            key_context.add("inline_completion");
 2180        }
 2181
 2182        key_context
 2183    }
 2184
 2185    pub fn new_file(
 2186        workspace: &mut Workspace,
 2187        _: &workspace::NewFile,
 2188        cx: &mut ViewContext<Workspace>,
 2189    ) {
 2190        Self::new_in_workspace(workspace, cx).detach_and_prompt_err(
 2191            "Failed to create buffer",
 2192            cx,
 2193            |e, _| match e.error_code() {
 2194                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2195                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2196                e.error_tag("required").unwrap_or("the latest version")
 2197            )),
 2198                _ => None,
 2199            },
 2200        );
 2201    }
 2202
 2203    pub fn new_in_workspace(
 2204        workspace: &mut Workspace,
 2205        cx: &mut ViewContext<Workspace>,
 2206    ) -> Task<Result<View<Editor>>> {
 2207        let project = workspace.project().clone();
 2208        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2209
 2210        cx.spawn(|workspace, mut cx| async move {
 2211            let buffer = create.await?;
 2212            workspace.update(&mut cx, |workspace, cx| {
 2213                let editor =
 2214                    cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx));
 2215                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx);
 2216                editor
 2217            })
 2218        })
 2219    }
 2220
 2221    fn new_file_vertical(
 2222        workspace: &mut Workspace,
 2223        _: &workspace::NewFileSplitVertical,
 2224        cx: &mut ViewContext<Workspace>,
 2225    ) {
 2226        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), cx)
 2227    }
 2228
 2229    fn new_file_horizontal(
 2230        workspace: &mut Workspace,
 2231        _: &workspace::NewFileSplitHorizontal,
 2232        cx: &mut ViewContext<Workspace>,
 2233    ) {
 2234        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), cx)
 2235    }
 2236
 2237    fn new_file_in_direction(
 2238        workspace: &mut Workspace,
 2239        direction: SplitDirection,
 2240        cx: &mut ViewContext<Workspace>,
 2241    ) {
 2242        let project = workspace.project().clone();
 2243        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2244
 2245        cx.spawn(|workspace, mut cx| async move {
 2246            let buffer = create.await?;
 2247            workspace.update(&mut cx, move |workspace, cx| {
 2248                workspace.split_item(
 2249                    direction,
 2250                    Box::new(
 2251                        cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
 2252                    ),
 2253                    cx,
 2254                )
 2255            })?;
 2256            anyhow::Ok(())
 2257        })
 2258        .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
 2259            ErrorCode::RemoteUpgradeRequired => Some(format!(
 2260                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2261                e.error_tag("required").unwrap_or("the latest version")
 2262            )),
 2263            _ => None,
 2264        });
 2265    }
 2266
 2267    pub fn leader_peer_id(&self) -> Option<PeerId> {
 2268        self.leader_peer_id
 2269    }
 2270
 2271    pub fn buffer(&self) -> &Model<MultiBuffer> {
 2272        &self.buffer
 2273    }
 2274
 2275    pub fn workspace(&self) -> Option<View<Workspace>> {
 2276        self.workspace.as_ref()?.0.upgrade()
 2277    }
 2278
 2279    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
 2280        self.buffer().read(cx).title(cx)
 2281    }
 2282
 2283    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
 2284        let git_blame_gutter_max_author_length = self
 2285            .render_git_blame_gutter(cx)
 2286            .then(|| {
 2287                if let Some(blame) = self.blame.as_ref() {
 2288                    let max_author_length =
 2289                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2290                    Some(max_author_length)
 2291                } else {
 2292                    None
 2293                }
 2294            })
 2295            .flatten();
 2296
 2297        EditorSnapshot {
 2298            mode: self.mode,
 2299            show_gutter: self.show_gutter,
 2300            show_line_numbers: self.show_line_numbers,
 2301            show_git_diff_gutter: self.show_git_diff_gutter,
 2302            show_code_actions: self.show_code_actions,
 2303            show_runnables: self.show_runnables,
 2304            git_blame_gutter_max_author_length,
 2305            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2306            scroll_anchor: self.scroll_manager.anchor(),
 2307            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2308            placeholder_text: self.placeholder_text.clone(),
 2309            is_focused: self.focus_handle.is_focused(cx),
 2310            current_line_highlight: self
 2311                .current_line_highlight
 2312                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2313            gutter_hovered: self.gutter_hovered,
 2314        }
 2315    }
 2316
 2317    pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
 2318        self.buffer.read(cx).language_at(point, cx)
 2319    }
 2320
 2321    pub fn file_at<T: ToOffset>(
 2322        &self,
 2323        point: T,
 2324        cx: &AppContext,
 2325    ) -> Option<Arc<dyn language::File>> {
 2326        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2327    }
 2328
 2329    pub fn active_excerpt(
 2330        &self,
 2331        cx: &AppContext,
 2332    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
 2333        self.buffer
 2334            .read(cx)
 2335            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2336    }
 2337
 2338    pub fn mode(&self) -> EditorMode {
 2339        self.mode
 2340    }
 2341
 2342    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2343        self.collaboration_hub.as_deref()
 2344    }
 2345
 2346    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2347        self.collaboration_hub = Some(hub);
 2348    }
 2349
 2350    pub fn set_custom_context_menu(
 2351        &mut self,
 2352        f: impl 'static
 2353            + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
 2354    ) {
 2355        self.custom_context_menu = Some(Box::new(f))
 2356    }
 2357
 2358    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2359        self.completion_provider = provider;
 2360    }
 2361
 2362    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2363        self.semantics_provider.clone()
 2364    }
 2365
 2366    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2367        self.semantics_provider = provider;
 2368    }
 2369
 2370    pub fn set_inline_completion_provider<T>(
 2371        &mut self,
 2372        provider: Option<Model<T>>,
 2373        cx: &mut ViewContext<Self>,
 2374    ) where
 2375        T: InlineCompletionProvider,
 2376    {
 2377        self.inline_completion_provider =
 2378            provider.map(|provider| RegisteredInlineCompletionProvider {
 2379                _subscription: cx.observe(&provider, |this, _, cx| {
 2380                    if this.focus_handle.is_focused(cx) {
 2381                        this.update_visible_inline_completion(cx);
 2382                    }
 2383                }),
 2384                provider: Arc::new(provider),
 2385            });
 2386        self.refresh_inline_completion(false, false, cx);
 2387    }
 2388
 2389    pub fn placeholder_text(&self, _cx: &WindowContext) -> Option<&str> {
 2390        self.placeholder_text.as_deref()
 2391    }
 2392
 2393    pub fn set_placeholder_text(
 2394        &mut self,
 2395        placeholder_text: impl Into<Arc<str>>,
 2396        cx: &mut ViewContext<Self>,
 2397    ) {
 2398        let placeholder_text = Some(placeholder_text.into());
 2399        if self.placeholder_text != placeholder_text {
 2400            self.placeholder_text = placeholder_text;
 2401            cx.notify();
 2402        }
 2403    }
 2404
 2405    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 2406        self.cursor_shape = cursor_shape;
 2407
 2408        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2409        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2410
 2411        cx.notify();
 2412    }
 2413
 2414    pub fn set_current_line_highlight(
 2415        &mut self,
 2416        current_line_highlight: Option<CurrentLineHighlight>,
 2417    ) {
 2418        self.current_line_highlight = current_line_highlight;
 2419    }
 2420
 2421    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2422        self.collapse_matches = collapse_matches;
 2423    }
 2424
 2425    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2426        if self.collapse_matches {
 2427            return range.start..range.start;
 2428        }
 2429        range.clone()
 2430    }
 2431
 2432    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 2433        if self.display_map.read(cx).clip_at_line_ends != clip {
 2434            self.display_map
 2435                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2436        }
 2437    }
 2438
 2439    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2440        self.input_enabled = input_enabled;
 2441    }
 2442
 2443    pub fn set_inline_completions_enabled(&mut self, enabled: bool) {
 2444        self.enable_inline_completions = enabled;
 2445    }
 2446
 2447    pub fn set_autoindent(&mut self, autoindent: bool) {
 2448        if autoindent {
 2449            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2450        } else {
 2451            self.autoindent_mode = None;
 2452        }
 2453    }
 2454
 2455    pub fn read_only(&self, cx: &AppContext) -> bool {
 2456        self.read_only || self.buffer.read(cx).read_only()
 2457    }
 2458
 2459    pub fn set_read_only(&mut self, read_only: bool) {
 2460        self.read_only = read_only;
 2461    }
 2462
 2463    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2464        self.use_autoclose = autoclose;
 2465    }
 2466
 2467    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2468        self.use_auto_surround = auto_surround;
 2469    }
 2470
 2471    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2472        self.auto_replace_emoji_shortcode = auto_replace;
 2473    }
 2474
 2475    pub fn toggle_inline_completions(
 2476        &mut self,
 2477        _: &ToggleInlineCompletions,
 2478        cx: &mut ViewContext<Self>,
 2479    ) {
 2480        if self.show_inline_completions_override.is_some() {
 2481            self.set_show_inline_completions(None, cx);
 2482        } else {
 2483            let cursor = self.selections.newest_anchor().head();
 2484            if let Some((buffer, cursor_buffer_position)) =
 2485                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 2486            {
 2487                let show_inline_completions =
 2488                    !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx);
 2489                self.set_show_inline_completions(Some(show_inline_completions), cx);
 2490            }
 2491        }
 2492    }
 2493
 2494    pub fn set_show_inline_completions(
 2495        &mut self,
 2496        show_inline_completions: Option<bool>,
 2497        cx: &mut ViewContext<Self>,
 2498    ) {
 2499        self.show_inline_completions_override = show_inline_completions;
 2500        self.refresh_inline_completion(false, true, cx);
 2501    }
 2502
 2503    fn should_show_inline_completions(
 2504        &self,
 2505        buffer: &Model<Buffer>,
 2506        buffer_position: language::Anchor,
 2507        cx: &AppContext,
 2508    ) -> bool {
 2509        if !self.snippet_stack.is_empty() {
 2510            return false;
 2511        }
 2512
 2513        if let Some(provider) = self.inline_completion_provider() {
 2514            if let Some(show_inline_completions) = self.show_inline_completions_override {
 2515                show_inline_completions
 2516            } else {
 2517                self.mode == EditorMode::Full && provider.is_enabled(buffer, buffer_position, cx)
 2518            }
 2519        } else {
 2520            false
 2521        }
 2522    }
 2523
 2524    pub fn set_use_modal_editing(&mut self, to: bool) {
 2525        self.use_modal_editing = to;
 2526    }
 2527
 2528    pub fn use_modal_editing(&self) -> bool {
 2529        self.use_modal_editing
 2530    }
 2531
 2532    fn selections_did_change(
 2533        &mut self,
 2534        local: bool,
 2535        old_cursor_position: &Anchor,
 2536        show_completions: bool,
 2537        cx: &mut ViewContext<Self>,
 2538    ) {
 2539        cx.invalidate_character_coordinates();
 2540
 2541        // Copy selections to primary selection buffer
 2542        #[cfg(target_os = "linux")]
 2543        if local {
 2544            let selections = self.selections.all::<usize>(cx);
 2545            let buffer_handle = self.buffer.read(cx).read(cx);
 2546
 2547            let mut text = String::new();
 2548            for (index, selection) in selections.iter().enumerate() {
 2549                let text_for_selection = buffer_handle
 2550                    .text_for_range(selection.start..selection.end)
 2551                    .collect::<String>();
 2552
 2553                text.push_str(&text_for_selection);
 2554                if index != selections.len() - 1 {
 2555                    text.push('\n');
 2556                }
 2557            }
 2558
 2559            if !text.is_empty() {
 2560                cx.write_to_primary(ClipboardItem::new_string(text));
 2561            }
 2562        }
 2563
 2564        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
 2565            self.buffer.update(cx, |buffer, cx| {
 2566                buffer.set_active_selections(
 2567                    &self.selections.disjoint_anchors(),
 2568                    self.selections.line_mode,
 2569                    self.cursor_shape,
 2570                    cx,
 2571                )
 2572            });
 2573        }
 2574        let display_map = self
 2575            .display_map
 2576            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2577        let buffer = &display_map.buffer_snapshot;
 2578        self.add_selections_state = None;
 2579        self.select_next_state = None;
 2580        self.select_prev_state = None;
 2581        self.select_larger_syntax_node_stack.clear();
 2582        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2583        self.snippet_stack
 2584            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2585        self.take_rename(false, cx);
 2586
 2587        let new_cursor_position = self.selections.newest_anchor().head();
 2588
 2589        self.push_to_nav_history(
 2590            *old_cursor_position,
 2591            Some(new_cursor_position.to_point(buffer)),
 2592            cx,
 2593        );
 2594
 2595        if local {
 2596            let new_cursor_position = self.selections.newest_anchor().head();
 2597            let mut context_menu = self.context_menu.write();
 2598            let completion_menu = match context_menu.as_ref() {
 2599                Some(ContextMenu::Completions(menu)) => Some(menu),
 2600
 2601                _ => {
 2602                    *context_menu = None;
 2603                    None
 2604                }
 2605            };
 2606
 2607            if let Some(completion_menu) = completion_menu {
 2608                let cursor_position = new_cursor_position.to_offset(buffer);
 2609                let (word_range, kind) =
 2610                    buffer.surrounding_word(completion_menu.initial_position, true);
 2611                if kind == Some(CharKind::Word)
 2612                    && word_range.to_inclusive().contains(&cursor_position)
 2613                {
 2614                    let mut completion_menu = completion_menu.clone();
 2615                    drop(context_menu);
 2616
 2617                    let query = Self::completion_query(buffer, cursor_position);
 2618                    cx.spawn(move |this, mut cx| async move {
 2619                        completion_menu
 2620                            .filter(query.as_deref(), cx.background_executor().clone())
 2621                            .await;
 2622
 2623                        this.update(&mut cx, |this, cx| {
 2624                            let mut context_menu = this.context_menu.write();
 2625                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
 2626                                return;
 2627                            };
 2628
 2629                            if menu.id > completion_menu.id {
 2630                                return;
 2631                            }
 2632
 2633                            *context_menu = Some(ContextMenu::Completions(completion_menu));
 2634                            drop(context_menu);
 2635                            cx.notify();
 2636                        })
 2637                    })
 2638                    .detach();
 2639
 2640                    if show_completions {
 2641                        self.show_completions(&ShowCompletions { trigger: None }, cx);
 2642                    }
 2643                } else {
 2644                    drop(context_menu);
 2645                    self.hide_context_menu(cx);
 2646                }
 2647            } else {
 2648                drop(context_menu);
 2649            }
 2650
 2651            hide_hover(self, cx);
 2652
 2653            if old_cursor_position.to_display_point(&display_map).row()
 2654                != new_cursor_position.to_display_point(&display_map).row()
 2655            {
 2656                self.available_code_actions.take();
 2657            }
 2658            self.refresh_code_actions(cx);
 2659            self.refresh_document_highlights(cx);
 2660            refresh_matching_bracket_highlights(self, cx);
 2661            self.discard_inline_completion(false, cx);
 2662            linked_editing_ranges::refresh_linked_ranges(self, cx);
 2663            if self.git_blame_inline_enabled {
 2664                self.start_inline_blame_timer(cx);
 2665            }
 2666        }
 2667
 2668        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2669        cx.emit(EditorEvent::SelectionsChanged { local });
 2670
 2671        if self.selections.disjoint_anchors().len() == 1 {
 2672            cx.emit(SearchEvent::ActiveMatchChanged)
 2673        }
 2674        cx.notify();
 2675    }
 2676
 2677    pub fn change_selections<R>(
 2678        &mut self,
 2679        autoscroll: Option<Autoscroll>,
 2680        cx: &mut ViewContext<Self>,
 2681        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2682    ) -> R {
 2683        self.change_selections_inner(autoscroll, true, cx, change)
 2684    }
 2685
 2686    pub fn change_selections_inner<R>(
 2687        &mut self,
 2688        autoscroll: Option<Autoscroll>,
 2689        request_completions: bool,
 2690        cx: &mut ViewContext<Self>,
 2691        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2692    ) -> R {
 2693        let old_cursor_position = self.selections.newest_anchor().head();
 2694        self.push_to_selection_history();
 2695
 2696        let (changed, result) = self.selections.change_with(cx, change);
 2697
 2698        if changed {
 2699            if let Some(autoscroll) = autoscroll {
 2700                self.request_autoscroll(autoscroll, cx);
 2701            }
 2702            self.selections_did_change(true, &old_cursor_position, request_completions, cx);
 2703
 2704            if self.should_open_signature_help_automatically(
 2705                &old_cursor_position,
 2706                self.signature_help_state.backspace_pressed(),
 2707                cx,
 2708            ) {
 2709                self.show_signature_help(&ShowSignatureHelp, cx);
 2710            }
 2711            self.signature_help_state.set_backspace_pressed(false);
 2712        }
 2713
 2714        result
 2715    }
 2716
 2717    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2718    where
 2719        I: IntoIterator<Item = (Range<S>, T)>,
 2720        S: ToOffset,
 2721        T: Into<Arc<str>>,
 2722    {
 2723        if self.read_only(cx) {
 2724            return;
 2725        }
 2726
 2727        self.buffer
 2728            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2729    }
 2730
 2731    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2732    where
 2733        I: IntoIterator<Item = (Range<S>, T)>,
 2734        S: ToOffset,
 2735        T: Into<Arc<str>>,
 2736    {
 2737        if self.read_only(cx) {
 2738            return;
 2739        }
 2740
 2741        self.buffer.update(cx, |buffer, cx| {
 2742            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2743        });
 2744    }
 2745
 2746    pub fn edit_with_block_indent<I, S, T>(
 2747        &mut self,
 2748        edits: I,
 2749        original_indent_columns: Vec<u32>,
 2750        cx: &mut ViewContext<Self>,
 2751    ) where
 2752        I: IntoIterator<Item = (Range<S>, T)>,
 2753        S: ToOffset,
 2754        T: Into<Arc<str>>,
 2755    {
 2756        if self.read_only(cx) {
 2757            return;
 2758        }
 2759
 2760        self.buffer.update(cx, |buffer, cx| {
 2761            buffer.edit(
 2762                edits,
 2763                Some(AutoindentMode::Block {
 2764                    original_indent_columns,
 2765                }),
 2766                cx,
 2767            )
 2768        });
 2769    }
 2770
 2771    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
 2772        self.hide_context_menu(cx);
 2773
 2774        match phase {
 2775            SelectPhase::Begin {
 2776                position,
 2777                add,
 2778                click_count,
 2779            } => self.begin_selection(position, add, click_count, cx),
 2780            SelectPhase::BeginColumnar {
 2781                position,
 2782                goal_column,
 2783                reset,
 2784            } => self.begin_columnar_selection(position, goal_column, reset, cx),
 2785            SelectPhase::Extend {
 2786                position,
 2787                click_count,
 2788            } => self.extend_selection(position, click_count, cx),
 2789            SelectPhase::Update {
 2790                position,
 2791                goal_column,
 2792                scroll_delta,
 2793            } => self.update_selection(position, goal_column, scroll_delta, cx),
 2794            SelectPhase::End => self.end_selection(cx),
 2795        }
 2796    }
 2797
 2798    fn extend_selection(
 2799        &mut self,
 2800        position: DisplayPoint,
 2801        click_count: usize,
 2802        cx: &mut ViewContext<Self>,
 2803    ) {
 2804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2805        let tail = self.selections.newest::<usize>(cx).tail();
 2806        self.begin_selection(position, false, click_count, cx);
 2807
 2808        let position = position.to_offset(&display_map, Bias::Left);
 2809        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2810
 2811        let mut pending_selection = self
 2812            .selections
 2813            .pending_anchor()
 2814            .expect("extend_selection not called with pending selection");
 2815        if position >= tail {
 2816            pending_selection.start = tail_anchor;
 2817        } else {
 2818            pending_selection.end = tail_anchor;
 2819            pending_selection.reversed = true;
 2820        }
 2821
 2822        let mut pending_mode = self.selections.pending_mode().unwrap();
 2823        match &mut pending_mode {
 2824            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2825            _ => {}
 2826        }
 2827
 2828        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2829            s.set_pending(pending_selection, pending_mode)
 2830        });
 2831    }
 2832
 2833    fn begin_selection(
 2834        &mut self,
 2835        position: DisplayPoint,
 2836        add: bool,
 2837        click_count: usize,
 2838        cx: &mut ViewContext<Self>,
 2839    ) {
 2840        if !self.focus_handle.is_focused(cx) {
 2841            self.last_focused_descendant = None;
 2842            cx.focus(&self.focus_handle);
 2843        }
 2844
 2845        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2846        let buffer = &display_map.buffer_snapshot;
 2847        let newest_selection = self.selections.newest_anchor().clone();
 2848        let position = display_map.clip_point(position, Bias::Left);
 2849
 2850        let start;
 2851        let end;
 2852        let mode;
 2853        let auto_scroll;
 2854        match click_count {
 2855            1 => {
 2856                start = buffer.anchor_before(position.to_point(&display_map));
 2857                end = start;
 2858                mode = SelectMode::Character;
 2859                auto_scroll = true;
 2860            }
 2861            2 => {
 2862                let range = movement::surrounding_word(&display_map, position);
 2863                start = buffer.anchor_before(range.start.to_point(&display_map));
 2864                end = buffer.anchor_before(range.end.to_point(&display_map));
 2865                mode = SelectMode::Word(start..end);
 2866                auto_scroll = true;
 2867            }
 2868            3 => {
 2869                let position = display_map
 2870                    .clip_point(position, Bias::Left)
 2871                    .to_point(&display_map);
 2872                let line_start = display_map.prev_line_boundary(position).0;
 2873                let next_line_start = buffer.clip_point(
 2874                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2875                    Bias::Left,
 2876                );
 2877                start = buffer.anchor_before(line_start);
 2878                end = buffer.anchor_before(next_line_start);
 2879                mode = SelectMode::Line(start..end);
 2880                auto_scroll = true;
 2881            }
 2882            _ => {
 2883                start = buffer.anchor_before(0);
 2884                end = buffer.anchor_before(buffer.len());
 2885                mode = SelectMode::All;
 2886                auto_scroll = false;
 2887            }
 2888        }
 2889
 2890        let point_to_delete: Option<usize> = {
 2891            let selected_points: Vec<Selection<Point>> =
 2892                self.selections.disjoint_in_range(start..end, cx);
 2893
 2894            if !add || click_count > 1 {
 2895                None
 2896            } else if !selected_points.is_empty() {
 2897                Some(selected_points[0].id)
 2898            } else {
 2899                let clicked_point_already_selected =
 2900                    self.selections.disjoint.iter().find(|selection| {
 2901                        selection.start.to_point(buffer) == start.to_point(buffer)
 2902                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2903                    });
 2904
 2905                clicked_point_already_selected.map(|selection| selection.id)
 2906            }
 2907        };
 2908
 2909        let selections_count = self.selections.count();
 2910
 2911        self.change_selections(auto_scroll.then(Autoscroll::newest), cx, |s| {
 2912            if let Some(point_to_delete) = point_to_delete {
 2913                s.delete(point_to_delete);
 2914
 2915                if selections_count == 1 {
 2916                    s.set_pending_anchor_range(start..end, mode);
 2917                }
 2918            } else {
 2919                if !add {
 2920                    s.clear_disjoint();
 2921                } else if click_count > 1 {
 2922                    s.delete(newest_selection.id)
 2923                }
 2924
 2925                s.set_pending_anchor_range(start..end, mode);
 2926            }
 2927        });
 2928    }
 2929
 2930    fn begin_columnar_selection(
 2931        &mut self,
 2932        position: DisplayPoint,
 2933        goal_column: u32,
 2934        reset: bool,
 2935        cx: &mut ViewContext<Self>,
 2936    ) {
 2937        if !self.focus_handle.is_focused(cx) {
 2938            self.last_focused_descendant = None;
 2939            cx.focus(&self.focus_handle);
 2940        }
 2941
 2942        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2943
 2944        if reset {
 2945            let pointer_position = display_map
 2946                .buffer_snapshot
 2947                .anchor_before(position.to_point(&display_map));
 2948
 2949            self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 2950                s.clear_disjoint();
 2951                s.set_pending_anchor_range(
 2952                    pointer_position..pointer_position,
 2953                    SelectMode::Character,
 2954                );
 2955            });
 2956        }
 2957
 2958        let tail = self.selections.newest::<Point>(cx).tail();
 2959        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2960
 2961        if !reset {
 2962            self.select_columns(
 2963                tail.to_display_point(&display_map),
 2964                position,
 2965                goal_column,
 2966                &display_map,
 2967                cx,
 2968            );
 2969        }
 2970    }
 2971
 2972    fn update_selection(
 2973        &mut self,
 2974        position: DisplayPoint,
 2975        goal_column: u32,
 2976        scroll_delta: gpui::Point<f32>,
 2977        cx: &mut ViewContext<Self>,
 2978    ) {
 2979        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2980
 2981        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2982            let tail = tail.to_display_point(&display_map);
 2983            self.select_columns(tail, position, goal_column, &display_map, cx);
 2984        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2985            let buffer = self.buffer.read(cx).snapshot(cx);
 2986            let head;
 2987            let tail;
 2988            let mode = self.selections.pending_mode().unwrap();
 2989            match &mode {
 2990                SelectMode::Character => {
 2991                    head = position.to_point(&display_map);
 2992                    tail = pending.tail().to_point(&buffer);
 2993                }
 2994                SelectMode::Word(original_range) => {
 2995                    let original_display_range = original_range.start.to_display_point(&display_map)
 2996                        ..original_range.end.to_display_point(&display_map);
 2997                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2998                        ..original_display_range.end.to_point(&display_map);
 2999                    if movement::is_inside_word(&display_map, position)
 3000                        || original_display_range.contains(&position)
 3001                    {
 3002                        let word_range = movement::surrounding_word(&display_map, position);
 3003                        if word_range.start < original_display_range.start {
 3004                            head = word_range.start.to_point(&display_map);
 3005                        } else {
 3006                            head = word_range.end.to_point(&display_map);
 3007                        }
 3008                    } else {
 3009                        head = position.to_point(&display_map);
 3010                    }
 3011
 3012                    if head <= original_buffer_range.start {
 3013                        tail = original_buffer_range.end;
 3014                    } else {
 3015                        tail = original_buffer_range.start;
 3016                    }
 3017                }
 3018                SelectMode::Line(original_range) => {
 3019                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3020
 3021                    let position = display_map
 3022                        .clip_point(position, Bias::Left)
 3023                        .to_point(&display_map);
 3024                    let line_start = display_map.prev_line_boundary(position).0;
 3025                    let next_line_start = buffer.clip_point(
 3026                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3027                        Bias::Left,
 3028                    );
 3029
 3030                    if line_start < original_range.start {
 3031                        head = line_start
 3032                    } else {
 3033                        head = next_line_start
 3034                    }
 3035
 3036                    if head <= original_range.start {
 3037                        tail = original_range.end;
 3038                    } else {
 3039                        tail = original_range.start;
 3040                    }
 3041                }
 3042                SelectMode::All => {
 3043                    return;
 3044                }
 3045            };
 3046
 3047            if head < tail {
 3048                pending.start = buffer.anchor_before(head);
 3049                pending.end = buffer.anchor_before(tail);
 3050                pending.reversed = true;
 3051            } else {
 3052                pending.start = buffer.anchor_before(tail);
 3053                pending.end = buffer.anchor_before(head);
 3054                pending.reversed = false;
 3055            }
 3056
 3057            self.change_selections(None, cx, |s| {
 3058                s.set_pending(pending, mode);
 3059            });
 3060        } else {
 3061            log::error!("update_selection dispatched with no pending selection");
 3062            return;
 3063        }
 3064
 3065        self.apply_scroll_delta(scroll_delta, cx);
 3066        cx.notify();
 3067    }
 3068
 3069    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 3070        self.columnar_selection_tail.take();
 3071        if self.selections.pending_anchor().is_some() {
 3072            let selections = self.selections.all::<usize>(cx);
 3073            self.change_selections(None, cx, |s| {
 3074                s.select(selections);
 3075                s.clear_pending();
 3076            });
 3077        }
 3078    }
 3079
 3080    fn select_columns(
 3081        &mut self,
 3082        tail: DisplayPoint,
 3083        head: DisplayPoint,
 3084        goal_column: u32,
 3085        display_map: &DisplaySnapshot,
 3086        cx: &mut ViewContext<Self>,
 3087    ) {
 3088        let start_row = cmp::min(tail.row(), head.row());
 3089        let end_row = cmp::max(tail.row(), head.row());
 3090        let start_column = cmp::min(tail.column(), goal_column);
 3091        let end_column = cmp::max(tail.column(), goal_column);
 3092        let reversed = start_column < tail.column();
 3093
 3094        let selection_ranges = (start_row.0..=end_row.0)
 3095            .map(DisplayRow)
 3096            .filter_map(|row| {
 3097                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3098                    let start = display_map
 3099                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3100                        .to_point(display_map);
 3101                    let end = display_map
 3102                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3103                        .to_point(display_map);
 3104                    if reversed {
 3105                        Some(end..start)
 3106                    } else {
 3107                        Some(start..end)
 3108                    }
 3109                } else {
 3110                    None
 3111                }
 3112            })
 3113            .collect::<Vec<_>>();
 3114
 3115        self.change_selections(None, cx, |s| {
 3116            s.select_ranges(selection_ranges);
 3117        });
 3118        cx.notify();
 3119    }
 3120
 3121    pub fn has_pending_nonempty_selection(&self) -> bool {
 3122        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3123            Some(Selection { start, end, .. }) => start != end,
 3124            None => false,
 3125        };
 3126
 3127        pending_nonempty_selection
 3128            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3129    }
 3130
 3131    pub fn has_pending_selection(&self) -> bool {
 3132        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3133    }
 3134
 3135    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 3136        if self.clear_expanded_diff_hunks(cx) {
 3137            cx.notify();
 3138            return;
 3139        }
 3140        if self.dismiss_menus_and_popups(true, cx) {
 3141            return;
 3142        }
 3143
 3144        if self.mode == EditorMode::Full
 3145            && self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel())
 3146        {
 3147            return;
 3148        }
 3149
 3150        cx.propagate();
 3151    }
 3152
 3153    pub fn dismiss_menus_and_popups(
 3154        &mut self,
 3155        should_report_inline_completion_event: bool,
 3156        cx: &mut ViewContext<Self>,
 3157    ) -> bool {
 3158        if self.take_rename(false, cx).is_some() {
 3159            return true;
 3160        }
 3161
 3162        if hide_hover(self, cx) {
 3163            return true;
 3164        }
 3165
 3166        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3167            return true;
 3168        }
 3169
 3170        if self.hide_context_menu(cx).is_some() {
 3171            return true;
 3172        }
 3173
 3174        if self.mouse_context_menu.take().is_some() {
 3175            return true;
 3176        }
 3177
 3178        if self.discard_inline_completion(should_report_inline_completion_event, cx) {
 3179            return true;
 3180        }
 3181
 3182        if self.snippet_stack.pop().is_some() {
 3183            return true;
 3184        }
 3185
 3186        if self.mode == EditorMode::Full && self.active_diagnostics.is_some() {
 3187            self.dismiss_diagnostics(cx);
 3188            return true;
 3189        }
 3190
 3191        false
 3192    }
 3193
 3194    fn linked_editing_ranges_for(
 3195        &self,
 3196        selection: Range<text::Anchor>,
 3197        cx: &AppContext,
 3198    ) -> Option<HashMap<Model<Buffer>, Vec<Range<text::Anchor>>>> {
 3199        if self.linked_edit_ranges.is_empty() {
 3200            return None;
 3201        }
 3202        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3203            selection.end.buffer_id.and_then(|end_buffer_id| {
 3204                if selection.start.buffer_id != Some(end_buffer_id) {
 3205                    return None;
 3206                }
 3207                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3208                let snapshot = buffer.read(cx).snapshot();
 3209                self.linked_edit_ranges
 3210                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3211                    .map(|ranges| (ranges, snapshot, buffer))
 3212            })?;
 3213        use text::ToOffset as TO;
 3214        // find offset from the start of current range to current cursor position
 3215        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3216
 3217        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3218        let start_difference = start_offset - start_byte_offset;
 3219        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3220        let end_difference = end_offset - start_byte_offset;
 3221        // Current range has associated linked ranges.
 3222        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3223        for range in linked_ranges.iter() {
 3224            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3225            let end_offset = start_offset + end_difference;
 3226            let start_offset = start_offset + start_difference;
 3227            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3228                continue;
 3229            }
 3230            if self.selections.disjoint_anchor_ranges().iter().any(|s| {
 3231                if s.start.buffer_id != selection.start.buffer_id
 3232                    || s.end.buffer_id != selection.end.buffer_id
 3233                {
 3234                    return false;
 3235                }
 3236                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3237                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3238            }) {
 3239                continue;
 3240            }
 3241            let start = buffer_snapshot.anchor_after(start_offset);
 3242            let end = buffer_snapshot.anchor_after(end_offset);
 3243            linked_edits
 3244                .entry(buffer.clone())
 3245                .or_default()
 3246                .push(start..end);
 3247        }
 3248        Some(linked_edits)
 3249    }
 3250
 3251    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 3252        let text: Arc<str> = text.into();
 3253
 3254        if self.read_only(cx) {
 3255            return;
 3256        }
 3257
 3258        let selections = self.selections.all_adjusted(cx);
 3259        let mut bracket_inserted = false;
 3260        let mut edits = Vec::new();
 3261        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3262        let mut new_selections = Vec::with_capacity(selections.len());
 3263        let mut new_autoclose_regions = Vec::new();
 3264        let snapshot = self.buffer.read(cx).read(cx);
 3265
 3266        for (selection, autoclose_region) in
 3267            self.selections_with_autoclose_regions(selections, &snapshot)
 3268        {
 3269            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3270                // Determine if the inserted text matches the opening or closing
 3271                // bracket of any of this language's bracket pairs.
 3272                let mut bracket_pair = None;
 3273                let mut is_bracket_pair_start = false;
 3274                let mut is_bracket_pair_end = false;
 3275                if !text.is_empty() {
 3276                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3277                    //  and they are removing the character that triggered IME popup.
 3278                    for (pair, enabled) in scope.brackets() {
 3279                        if !pair.close && !pair.surround {
 3280                            continue;
 3281                        }
 3282
 3283                        if enabled && pair.start.ends_with(text.as_ref()) {
 3284                            let prefix_len = pair.start.len() - text.len();
 3285                            let preceding_text_matches_prefix = prefix_len == 0
 3286                                || (selection.start.column >= (prefix_len as u32)
 3287                                    && snapshot.contains_str_at(
 3288                                        Point::new(
 3289                                            selection.start.row,
 3290                                            selection.start.column - (prefix_len as u32),
 3291                                        ),
 3292                                        &pair.start[..prefix_len],
 3293                                    ));
 3294                            if preceding_text_matches_prefix {
 3295                                bracket_pair = Some(pair.clone());
 3296                                is_bracket_pair_start = true;
 3297                                break;
 3298                            }
 3299                        }
 3300                        if pair.end.as_str() == text.as_ref() {
 3301                            bracket_pair = Some(pair.clone());
 3302                            is_bracket_pair_end = true;
 3303                            break;
 3304                        }
 3305                    }
 3306                }
 3307
 3308                if let Some(bracket_pair) = bracket_pair {
 3309                    let snapshot_settings = snapshot.settings_at(selection.start, cx);
 3310                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3311                    let auto_surround =
 3312                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3313                    if selection.is_empty() {
 3314                        if is_bracket_pair_start {
 3315                            // If the inserted text is a suffix of an opening bracket and the
 3316                            // selection is preceded by the rest of the opening bracket, then
 3317                            // insert the closing bracket.
 3318                            let following_text_allows_autoclose = snapshot
 3319                                .chars_at(selection.start)
 3320                                .next()
 3321                                .map_or(true, |c| scope.should_autoclose_before(c));
 3322
 3323                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3324                                && bracket_pair.start.len() == 1
 3325                            {
 3326                                let target = bracket_pair.start.chars().next().unwrap();
 3327                                let current_line_count = snapshot
 3328                                    .reversed_chars_at(selection.start)
 3329                                    .take_while(|&c| c != '\n')
 3330                                    .filter(|&c| c == target)
 3331                                    .count();
 3332                                current_line_count % 2 == 1
 3333                            } else {
 3334                                false
 3335                            };
 3336
 3337                            if autoclose
 3338                                && bracket_pair.close
 3339                                && following_text_allows_autoclose
 3340                                && !is_closing_quote
 3341                            {
 3342                                let anchor = snapshot.anchor_before(selection.end);
 3343                                new_selections.push((selection.map(|_| anchor), text.len()));
 3344                                new_autoclose_regions.push((
 3345                                    anchor,
 3346                                    text.len(),
 3347                                    selection.id,
 3348                                    bracket_pair.clone(),
 3349                                ));
 3350                                edits.push((
 3351                                    selection.range(),
 3352                                    format!("{}{}", text, bracket_pair.end).into(),
 3353                                ));
 3354                                bracket_inserted = true;
 3355                                continue;
 3356                            }
 3357                        }
 3358
 3359                        if let Some(region) = autoclose_region {
 3360                            // If the selection is followed by an auto-inserted closing bracket,
 3361                            // then don't insert that closing bracket again; just move the selection
 3362                            // past the closing bracket.
 3363                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3364                                && text.as_ref() == region.pair.end.as_str();
 3365                            if should_skip {
 3366                                let anchor = snapshot.anchor_after(selection.end);
 3367                                new_selections
 3368                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3369                                continue;
 3370                            }
 3371                        }
 3372
 3373                        let always_treat_brackets_as_autoclosed = snapshot
 3374                            .settings_at(selection.start, cx)
 3375                            .always_treat_brackets_as_autoclosed;
 3376                        if always_treat_brackets_as_autoclosed
 3377                            && is_bracket_pair_end
 3378                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3379                        {
 3380                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3381                            // and the inserted text is a closing bracket and the selection is followed
 3382                            // by the closing bracket then move the selection past the closing bracket.
 3383                            let anchor = snapshot.anchor_after(selection.end);
 3384                            new_selections.push((selection.map(|_| anchor), text.len()));
 3385                            continue;
 3386                        }
 3387                    }
 3388                    // If an opening bracket is 1 character long and is typed while
 3389                    // text is selected, then surround that text with the bracket pair.
 3390                    else if auto_surround
 3391                        && bracket_pair.surround
 3392                        && is_bracket_pair_start
 3393                        && bracket_pair.start.chars().count() == 1
 3394                    {
 3395                        edits.push((selection.start..selection.start, text.clone()));
 3396                        edits.push((
 3397                            selection.end..selection.end,
 3398                            bracket_pair.end.as_str().into(),
 3399                        ));
 3400                        bracket_inserted = true;
 3401                        new_selections.push((
 3402                            Selection {
 3403                                id: selection.id,
 3404                                start: snapshot.anchor_after(selection.start),
 3405                                end: snapshot.anchor_before(selection.end),
 3406                                reversed: selection.reversed,
 3407                                goal: selection.goal,
 3408                            },
 3409                            0,
 3410                        ));
 3411                        continue;
 3412                    }
 3413                }
 3414            }
 3415
 3416            if self.auto_replace_emoji_shortcode
 3417                && selection.is_empty()
 3418                && text.as_ref().ends_with(':')
 3419            {
 3420                if let Some(possible_emoji_short_code) =
 3421                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3422                {
 3423                    if !possible_emoji_short_code.is_empty() {
 3424                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3425                            let emoji_shortcode_start = Point::new(
 3426                                selection.start.row,
 3427                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3428                            );
 3429
 3430                            // Remove shortcode from buffer
 3431                            edits.push((
 3432                                emoji_shortcode_start..selection.start,
 3433                                "".to_string().into(),
 3434                            ));
 3435                            new_selections.push((
 3436                                Selection {
 3437                                    id: selection.id,
 3438                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3439                                    end: snapshot.anchor_before(selection.start),
 3440                                    reversed: selection.reversed,
 3441                                    goal: selection.goal,
 3442                                },
 3443                                0,
 3444                            ));
 3445
 3446                            // Insert emoji
 3447                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3448                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3449                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3450
 3451                            continue;
 3452                        }
 3453                    }
 3454                }
 3455            }
 3456
 3457            // If not handling any auto-close operation, then just replace the selected
 3458            // text with the given input and move the selection to the end of the
 3459            // newly inserted text.
 3460            let anchor = snapshot.anchor_after(selection.end);
 3461            if !self.linked_edit_ranges.is_empty() {
 3462                let start_anchor = snapshot.anchor_before(selection.start);
 3463
 3464                let is_word_char = text.chars().next().map_or(true, |char| {
 3465                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3466                    classifier.is_word(char)
 3467                });
 3468
 3469                if is_word_char {
 3470                    if let Some(ranges) = self
 3471                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3472                    {
 3473                        for (buffer, edits) in ranges {
 3474                            linked_edits
 3475                                .entry(buffer.clone())
 3476                                .or_default()
 3477                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3478                        }
 3479                    }
 3480                }
 3481            }
 3482
 3483            new_selections.push((selection.map(|_| anchor), 0));
 3484            edits.push((selection.start..selection.end, text.clone()));
 3485        }
 3486
 3487        drop(snapshot);
 3488
 3489        self.transact(cx, |this, cx| {
 3490            this.buffer.update(cx, |buffer, cx| {
 3491                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3492            });
 3493            for (buffer, edits) in linked_edits {
 3494                buffer.update(cx, |buffer, cx| {
 3495                    let snapshot = buffer.snapshot();
 3496                    let edits = edits
 3497                        .into_iter()
 3498                        .map(|(range, text)| {
 3499                            use text::ToPoint as TP;
 3500                            let end_point = TP::to_point(&range.end, &snapshot);
 3501                            let start_point = TP::to_point(&range.start, &snapshot);
 3502                            (start_point..end_point, text)
 3503                        })
 3504                        .sorted_by_key(|(range, _)| range.start)
 3505                        .collect::<Vec<_>>();
 3506                    buffer.edit(edits, None, cx);
 3507                })
 3508            }
 3509            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3510            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3511            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3512            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3513                .zip(new_selection_deltas)
 3514                .map(|(selection, delta)| Selection {
 3515                    id: selection.id,
 3516                    start: selection.start + delta,
 3517                    end: selection.end + delta,
 3518                    reversed: selection.reversed,
 3519                    goal: SelectionGoal::None,
 3520                })
 3521                .collect::<Vec<_>>();
 3522
 3523            let mut i = 0;
 3524            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3525                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3526                let start = map.buffer_snapshot.anchor_before(position);
 3527                let end = map.buffer_snapshot.anchor_after(position);
 3528                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3529                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3530                        Ordering::Less => i += 1,
 3531                        Ordering::Greater => break,
 3532                        Ordering::Equal => {
 3533                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3534                                Ordering::Less => i += 1,
 3535                                Ordering::Equal => break,
 3536                                Ordering::Greater => break,
 3537                            }
 3538                        }
 3539                    }
 3540                }
 3541                this.autoclose_regions.insert(
 3542                    i,
 3543                    AutocloseRegion {
 3544                        selection_id,
 3545                        range: start..end,
 3546                        pair,
 3547                    },
 3548                );
 3549            }
 3550
 3551            let had_active_inline_completion = this.has_active_inline_completion(cx);
 3552            this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| {
 3553                s.select(new_selections)
 3554            });
 3555
 3556            if !bracket_inserted {
 3557                if let Some(on_type_format_task) =
 3558                    this.trigger_on_type_formatting(text.to_string(), cx)
 3559                {
 3560                    on_type_format_task.detach_and_log_err(cx);
 3561                }
 3562            }
 3563
 3564            let editor_settings = EditorSettings::get_global(cx);
 3565            if bracket_inserted
 3566                && (editor_settings.auto_signature_help
 3567                    || editor_settings.show_signature_help_after_edits)
 3568            {
 3569                this.show_signature_help(&ShowSignatureHelp, cx);
 3570            }
 3571
 3572            let trigger_in_words = !had_active_inline_completion;
 3573            this.trigger_completion_on_input(&text, trigger_in_words, cx);
 3574            linked_editing_ranges::refresh_linked_ranges(this, cx);
 3575            this.refresh_inline_completion(true, false, cx);
 3576        });
 3577    }
 3578
 3579    fn find_possible_emoji_shortcode_at_position(
 3580        snapshot: &MultiBufferSnapshot,
 3581        position: Point,
 3582    ) -> Option<String> {
 3583        let mut chars = Vec::new();
 3584        let mut found_colon = false;
 3585        for char in snapshot.reversed_chars_at(position).take(100) {
 3586            // Found a possible emoji shortcode in the middle of the buffer
 3587            if found_colon {
 3588                if char.is_whitespace() {
 3589                    chars.reverse();
 3590                    return Some(chars.iter().collect());
 3591                }
 3592                // If the previous character is not a whitespace, we are in the middle of a word
 3593                // and we only want to complete the shortcode if the word is made up of other emojis
 3594                let mut containing_word = String::new();
 3595                for ch in snapshot
 3596                    .reversed_chars_at(position)
 3597                    .skip(chars.len() + 1)
 3598                    .take(100)
 3599                {
 3600                    if ch.is_whitespace() {
 3601                        break;
 3602                    }
 3603                    containing_word.push(ch);
 3604                }
 3605                let containing_word = containing_word.chars().rev().collect::<String>();
 3606                if util::word_consists_of_emojis(containing_word.as_str()) {
 3607                    chars.reverse();
 3608                    return Some(chars.iter().collect());
 3609                }
 3610            }
 3611
 3612            if char.is_whitespace() || !char.is_ascii() {
 3613                return None;
 3614            }
 3615            if char == ':' {
 3616                found_colon = true;
 3617            } else {
 3618                chars.push(char);
 3619            }
 3620        }
 3621        // Found a possible emoji shortcode at the beginning of the buffer
 3622        chars.reverse();
 3623        Some(chars.iter().collect())
 3624    }
 3625
 3626    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 3627        self.transact(cx, |this, cx| {
 3628            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3629                let selections = this.selections.all::<usize>(cx);
 3630                let multi_buffer = this.buffer.read(cx);
 3631                let buffer = multi_buffer.snapshot(cx);
 3632                selections
 3633                    .iter()
 3634                    .map(|selection| {
 3635                        let start_point = selection.start.to_point(&buffer);
 3636                        let mut indent =
 3637                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3638                        indent.len = cmp::min(indent.len, start_point.column);
 3639                        let start = selection.start;
 3640                        let end = selection.end;
 3641                        let selection_is_empty = start == end;
 3642                        let language_scope = buffer.language_scope_at(start);
 3643                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3644                            &language_scope
 3645                        {
 3646                            let leading_whitespace_len = buffer
 3647                                .reversed_chars_at(start)
 3648                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3649                                .map(|c| c.len_utf8())
 3650                                .sum::<usize>();
 3651
 3652                            let trailing_whitespace_len = buffer
 3653                                .chars_at(end)
 3654                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3655                                .map(|c| c.len_utf8())
 3656                                .sum::<usize>();
 3657
 3658                            let insert_extra_newline =
 3659                                language.brackets().any(|(pair, enabled)| {
 3660                                    let pair_start = pair.start.trim_end();
 3661                                    let pair_end = pair.end.trim_start();
 3662
 3663                                    enabled
 3664                                        && pair.newline
 3665                                        && buffer.contains_str_at(
 3666                                            end + trailing_whitespace_len,
 3667                                            pair_end,
 3668                                        )
 3669                                        && buffer.contains_str_at(
 3670                                            (start - leading_whitespace_len)
 3671                                                .saturating_sub(pair_start.len()),
 3672                                            pair_start,
 3673                                        )
 3674                                });
 3675
 3676                            // Comment extension on newline is allowed only for cursor selections
 3677                            let comment_delimiter = maybe!({
 3678                                if !selection_is_empty {
 3679                                    return None;
 3680                                }
 3681
 3682                                if !multi_buffer.settings_at(0, cx).extend_comment_on_newline {
 3683                                    return None;
 3684                                }
 3685
 3686                                let delimiters = language.line_comment_prefixes();
 3687                                let max_len_of_delimiter =
 3688                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3689                                let (snapshot, range) =
 3690                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3691
 3692                                let mut index_of_first_non_whitespace = 0;
 3693                                let comment_candidate = snapshot
 3694                                    .chars_for_range(range)
 3695                                    .skip_while(|c| {
 3696                                        let should_skip = c.is_whitespace();
 3697                                        if should_skip {
 3698                                            index_of_first_non_whitespace += 1;
 3699                                        }
 3700                                        should_skip
 3701                                    })
 3702                                    .take(max_len_of_delimiter)
 3703                                    .collect::<String>();
 3704                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3705                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3706                                })?;
 3707                                let cursor_is_placed_after_comment_marker =
 3708                                    index_of_first_non_whitespace + comment_prefix.len()
 3709                                        <= start_point.column as usize;
 3710                                if cursor_is_placed_after_comment_marker {
 3711                                    Some(comment_prefix.clone())
 3712                                } else {
 3713                                    None
 3714                                }
 3715                            });
 3716                            (comment_delimiter, insert_extra_newline)
 3717                        } else {
 3718                            (None, false)
 3719                        };
 3720
 3721                        let capacity_for_delimiter = comment_delimiter
 3722                            .as_deref()
 3723                            .map(str::len)
 3724                            .unwrap_or_default();
 3725                        let mut new_text =
 3726                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3727                        new_text.push('\n');
 3728                        new_text.extend(indent.chars());
 3729                        if let Some(delimiter) = &comment_delimiter {
 3730                            new_text.push_str(delimiter);
 3731                        }
 3732                        if insert_extra_newline {
 3733                            new_text = new_text.repeat(2);
 3734                        }
 3735
 3736                        let anchor = buffer.anchor_after(end);
 3737                        let new_selection = selection.map(|_| anchor);
 3738                        (
 3739                            (start..end, new_text),
 3740                            (insert_extra_newline, new_selection),
 3741                        )
 3742                    })
 3743                    .unzip()
 3744            };
 3745
 3746            this.edit_with_autoindent(edits, cx);
 3747            let buffer = this.buffer.read(cx).snapshot(cx);
 3748            let new_selections = selection_fixup_info
 3749                .into_iter()
 3750                .map(|(extra_newline_inserted, new_selection)| {
 3751                    let mut cursor = new_selection.end.to_point(&buffer);
 3752                    if extra_newline_inserted {
 3753                        cursor.row -= 1;
 3754                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3755                    }
 3756                    new_selection.map(|_| cursor)
 3757                })
 3758                .collect();
 3759
 3760            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 3761            this.refresh_inline_completion(true, false, cx);
 3762        });
 3763    }
 3764
 3765    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
 3766        let buffer = self.buffer.read(cx);
 3767        let snapshot = buffer.snapshot(cx);
 3768
 3769        let mut edits = Vec::new();
 3770        let mut rows = Vec::new();
 3771
 3772        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3773            let cursor = selection.head();
 3774            let row = cursor.row;
 3775
 3776            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3777
 3778            let newline = "\n".to_string();
 3779            edits.push((start_of_line..start_of_line, newline));
 3780
 3781            rows.push(row + rows_inserted as u32);
 3782        }
 3783
 3784        self.transact(cx, |editor, cx| {
 3785            editor.edit(edits, cx);
 3786
 3787            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3788                let mut index = 0;
 3789                s.move_cursors_with(|map, _, _| {
 3790                    let row = rows[index];
 3791                    index += 1;
 3792
 3793                    let point = Point::new(row, 0);
 3794                    let boundary = map.next_line_boundary(point).1;
 3795                    let clipped = map.clip_point(boundary, Bias::Left);
 3796
 3797                    (clipped, SelectionGoal::None)
 3798                });
 3799            });
 3800
 3801            let mut indent_edits = Vec::new();
 3802            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3803            for row in rows {
 3804                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3805                for (row, indent) in indents {
 3806                    if indent.len == 0 {
 3807                        continue;
 3808                    }
 3809
 3810                    let text = match indent.kind {
 3811                        IndentKind::Space => " ".repeat(indent.len as usize),
 3812                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3813                    };
 3814                    let point = Point::new(row.0, 0);
 3815                    indent_edits.push((point..point, text));
 3816                }
 3817            }
 3818            editor.edit(indent_edits, cx);
 3819        });
 3820    }
 3821
 3822    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
 3823        let buffer = self.buffer.read(cx);
 3824        let snapshot = buffer.snapshot(cx);
 3825
 3826        let mut edits = Vec::new();
 3827        let mut rows = Vec::new();
 3828        let mut rows_inserted = 0;
 3829
 3830        for selection in self.selections.all_adjusted(cx) {
 3831            let cursor = selection.head();
 3832            let row = cursor.row;
 3833
 3834            let point = Point::new(row + 1, 0);
 3835            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3836
 3837            let newline = "\n".to_string();
 3838            edits.push((start_of_line..start_of_line, newline));
 3839
 3840            rows_inserted += 1;
 3841            rows.push(row + rows_inserted);
 3842        }
 3843
 3844        self.transact(cx, |editor, cx| {
 3845            editor.edit(edits, cx);
 3846
 3847            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3848                let mut index = 0;
 3849                s.move_cursors_with(|map, _, _| {
 3850                    let row = rows[index];
 3851                    index += 1;
 3852
 3853                    let point = Point::new(row, 0);
 3854                    let boundary = map.next_line_boundary(point).1;
 3855                    let clipped = map.clip_point(boundary, Bias::Left);
 3856
 3857                    (clipped, SelectionGoal::None)
 3858                });
 3859            });
 3860
 3861            let mut indent_edits = Vec::new();
 3862            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3863            for row in rows {
 3864                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3865                for (row, indent) in indents {
 3866                    if indent.len == 0 {
 3867                        continue;
 3868                    }
 3869
 3870                    let text = match indent.kind {
 3871                        IndentKind::Space => " ".repeat(indent.len as usize),
 3872                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3873                    };
 3874                    let point = Point::new(row.0, 0);
 3875                    indent_edits.push((point..point, text));
 3876                }
 3877            }
 3878            editor.edit(indent_edits, cx);
 3879        });
 3880    }
 3881
 3882    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 3883        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3884            original_indent_columns: Vec::new(),
 3885        });
 3886        self.insert_with_autoindent_mode(text, autoindent, cx);
 3887    }
 3888
 3889    fn insert_with_autoindent_mode(
 3890        &mut self,
 3891        text: &str,
 3892        autoindent_mode: Option<AutoindentMode>,
 3893        cx: &mut ViewContext<Self>,
 3894    ) {
 3895        if self.read_only(cx) {
 3896            return;
 3897        }
 3898
 3899        let text: Arc<str> = text.into();
 3900        self.transact(cx, |this, cx| {
 3901            let old_selections = this.selections.all_adjusted(cx);
 3902            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3903                let anchors = {
 3904                    let snapshot = buffer.read(cx);
 3905                    old_selections
 3906                        .iter()
 3907                        .map(|s| {
 3908                            let anchor = snapshot.anchor_after(s.head());
 3909                            s.map(|_| anchor)
 3910                        })
 3911                        .collect::<Vec<_>>()
 3912                };
 3913                buffer.edit(
 3914                    old_selections
 3915                        .iter()
 3916                        .map(|s| (s.start..s.end, text.clone())),
 3917                    autoindent_mode,
 3918                    cx,
 3919                );
 3920                anchors
 3921            });
 3922
 3923            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3924                s.select_anchors(selection_anchors);
 3925            })
 3926        });
 3927    }
 3928
 3929    fn trigger_completion_on_input(
 3930        &mut self,
 3931        text: &str,
 3932        trigger_in_words: bool,
 3933        cx: &mut ViewContext<Self>,
 3934    ) {
 3935        if self.is_completion_trigger(text, trigger_in_words, cx) {
 3936            self.show_completions(
 3937                &ShowCompletions {
 3938                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 3939                },
 3940                cx,
 3941            );
 3942        } else {
 3943            self.hide_context_menu(cx);
 3944        }
 3945    }
 3946
 3947    fn is_completion_trigger(
 3948        &self,
 3949        text: &str,
 3950        trigger_in_words: bool,
 3951        cx: &mut ViewContext<Self>,
 3952    ) -> bool {
 3953        let position = self.selections.newest_anchor().head();
 3954        let multibuffer = self.buffer.read(cx);
 3955        let Some(buffer) = position
 3956            .buffer_id
 3957            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 3958        else {
 3959            return false;
 3960        };
 3961
 3962        if let Some(completion_provider) = &self.completion_provider {
 3963            completion_provider.is_completion_trigger(
 3964                &buffer,
 3965                position.text_anchor,
 3966                text,
 3967                trigger_in_words,
 3968                cx,
 3969            )
 3970        } else {
 3971            false
 3972        }
 3973    }
 3974
 3975    /// If any empty selections is touching the start of its innermost containing autoclose
 3976    /// region, expand it to select the brackets.
 3977    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
 3978        let selections = self.selections.all::<usize>(cx);
 3979        let buffer = self.buffer.read(cx).read(cx);
 3980        let new_selections = self
 3981            .selections_with_autoclose_regions(selections, &buffer)
 3982            .map(|(mut selection, region)| {
 3983                if !selection.is_empty() {
 3984                    return selection;
 3985                }
 3986
 3987                if let Some(region) = region {
 3988                    let mut range = region.range.to_offset(&buffer);
 3989                    if selection.start == range.start && range.start >= region.pair.start.len() {
 3990                        range.start -= region.pair.start.len();
 3991                        if buffer.contains_str_at(range.start, &region.pair.start)
 3992                            && buffer.contains_str_at(range.end, &region.pair.end)
 3993                        {
 3994                            range.end += region.pair.end.len();
 3995                            selection.start = range.start;
 3996                            selection.end = range.end;
 3997
 3998                            return selection;
 3999                        }
 4000                    }
 4001                }
 4002
 4003                let always_treat_brackets_as_autoclosed = buffer
 4004                    .settings_at(selection.start, cx)
 4005                    .always_treat_brackets_as_autoclosed;
 4006
 4007                if !always_treat_brackets_as_autoclosed {
 4008                    return selection;
 4009                }
 4010
 4011                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4012                    for (pair, enabled) in scope.brackets() {
 4013                        if !enabled || !pair.close {
 4014                            continue;
 4015                        }
 4016
 4017                        if buffer.contains_str_at(selection.start, &pair.end) {
 4018                            let pair_start_len = pair.start.len();
 4019                            if buffer.contains_str_at(selection.start - pair_start_len, &pair.start)
 4020                            {
 4021                                selection.start -= pair_start_len;
 4022                                selection.end += pair.end.len();
 4023
 4024                                return selection;
 4025                            }
 4026                        }
 4027                    }
 4028                }
 4029
 4030                selection
 4031            })
 4032            .collect();
 4033
 4034        drop(buffer);
 4035        self.change_selections(None, cx, |selections| selections.select(new_selections));
 4036    }
 4037
 4038    /// Iterate the given selections, and for each one, find the smallest surrounding
 4039    /// autoclose region. This uses the ordering of the selections and the autoclose
 4040    /// regions to avoid repeated comparisons.
 4041    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4042        &'a self,
 4043        selections: impl IntoIterator<Item = Selection<D>>,
 4044        buffer: &'a MultiBufferSnapshot,
 4045    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4046        let mut i = 0;
 4047        let mut regions = self.autoclose_regions.as_slice();
 4048        selections.into_iter().map(move |selection| {
 4049            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4050
 4051            let mut enclosing = None;
 4052            while let Some(pair_state) = regions.get(i) {
 4053                if pair_state.range.end.to_offset(buffer) < range.start {
 4054                    regions = &regions[i + 1..];
 4055                    i = 0;
 4056                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4057                    break;
 4058                } else {
 4059                    if pair_state.selection_id == selection.id {
 4060                        enclosing = Some(pair_state);
 4061                    }
 4062                    i += 1;
 4063                }
 4064            }
 4065
 4066            (selection, enclosing)
 4067        })
 4068    }
 4069
 4070    /// Remove any autoclose regions that no longer contain their selection.
 4071    fn invalidate_autoclose_regions(
 4072        &mut self,
 4073        mut selections: &[Selection<Anchor>],
 4074        buffer: &MultiBufferSnapshot,
 4075    ) {
 4076        self.autoclose_regions.retain(|state| {
 4077            let mut i = 0;
 4078            while let Some(selection) = selections.get(i) {
 4079                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4080                    selections = &selections[1..];
 4081                    continue;
 4082                }
 4083                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4084                    break;
 4085                }
 4086                if selection.id == state.selection_id {
 4087                    return true;
 4088                } else {
 4089                    i += 1;
 4090                }
 4091            }
 4092            false
 4093        });
 4094    }
 4095
 4096    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4097        let offset = position.to_offset(buffer);
 4098        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4099        if offset > word_range.start && kind == Some(CharKind::Word) {
 4100            Some(
 4101                buffer
 4102                    .text_for_range(word_range.start..offset)
 4103                    .collect::<String>(),
 4104            )
 4105        } else {
 4106            None
 4107        }
 4108    }
 4109
 4110    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
 4111        self.refresh_inlay_hints(
 4112            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
 4113            cx,
 4114        );
 4115    }
 4116
 4117    pub fn inlay_hints_enabled(&self) -> bool {
 4118        self.inlay_hint_cache.enabled
 4119    }
 4120
 4121    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
 4122        if self.semantics_provider.is_none() || self.mode != EditorMode::Full {
 4123            return;
 4124        }
 4125
 4126        let reason_description = reason.description();
 4127        let ignore_debounce = matches!(
 4128            reason,
 4129            InlayHintRefreshReason::SettingsChange(_)
 4130                | InlayHintRefreshReason::Toggle(_)
 4131                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4132        );
 4133        let (invalidate_cache, required_languages) = match reason {
 4134            InlayHintRefreshReason::Toggle(enabled) => {
 4135                self.inlay_hint_cache.enabled = enabled;
 4136                if enabled {
 4137                    (InvalidationStrategy::RefreshRequested, None)
 4138                } else {
 4139                    self.inlay_hint_cache.clear();
 4140                    self.splice_inlays(
 4141                        self.visible_inlay_hints(cx)
 4142                            .iter()
 4143                            .map(|inlay| inlay.id)
 4144                            .collect(),
 4145                        Vec::new(),
 4146                        cx,
 4147                    );
 4148                    return;
 4149                }
 4150            }
 4151            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4152                match self.inlay_hint_cache.update_settings(
 4153                    &self.buffer,
 4154                    new_settings,
 4155                    self.visible_inlay_hints(cx),
 4156                    cx,
 4157                ) {
 4158                    ControlFlow::Break(Some(InlaySplice {
 4159                        to_remove,
 4160                        to_insert,
 4161                    })) => {
 4162                        self.splice_inlays(to_remove, to_insert, cx);
 4163                        return;
 4164                    }
 4165                    ControlFlow::Break(None) => return,
 4166                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4167                }
 4168            }
 4169            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4170                if let Some(InlaySplice {
 4171                    to_remove,
 4172                    to_insert,
 4173                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 4174                {
 4175                    self.splice_inlays(to_remove, to_insert, cx);
 4176                }
 4177                return;
 4178            }
 4179            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4180            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4181                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4182            }
 4183            InlayHintRefreshReason::RefreshRequested => {
 4184                (InvalidationStrategy::RefreshRequested, None)
 4185            }
 4186        };
 4187
 4188        if let Some(InlaySplice {
 4189            to_remove,
 4190            to_insert,
 4191        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4192            reason_description,
 4193            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4194            invalidate_cache,
 4195            ignore_debounce,
 4196            cx,
 4197        ) {
 4198            self.splice_inlays(to_remove, to_insert, cx);
 4199        }
 4200    }
 4201
 4202    fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
 4203        self.display_map
 4204            .read(cx)
 4205            .current_inlays()
 4206            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4207            .cloned()
 4208            .collect()
 4209    }
 4210
 4211    pub fn excerpts_for_inlay_hints_query(
 4212        &self,
 4213        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4214        cx: &mut ViewContext<Editor>,
 4215    ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
 4216        let Some(project) = self.project.as_ref() else {
 4217            return HashMap::default();
 4218        };
 4219        let project = project.read(cx);
 4220        let multi_buffer = self.buffer().read(cx);
 4221        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4222        let multi_buffer_visible_start = self
 4223            .scroll_manager
 4224            .anchor()
 4225            .anchor
 4226            .to_point(&multi_buffer_snapshot);
 4227        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4228            multi_buffer_visible_start
 4229                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4230            Bias::Left,
 4231        );
 4232        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4233        multi_buffer
 4234            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
 4235            .into_iter()
 4236            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4237            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
 4238                let buffer = buffer_handle.read(cx);
 4239                let buffer_file = project::File::from_dyn(buffer.file())?;
 4240                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4241                let worktree_entry = buffer_worktree
 4242                    .read(cx)
 4243                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4244                if worktree_entry.is_ignored {
 4245                    return None;
 4246                }
 4247
 4248                let language = buffer.language()?;
 4249                if let Some(restrict_to_languages) = restrict_to_languages {
 4250                    if !restrict_to_languages.contains(language) {
 4251                        return None;
 4252                    }
 4253                }
 4254                Some((
 4255                    excerpt_id,
 4256                    (
 4257                        buffer_handle,
 4258                        buffer.version().clone(),
 4259                        excerpt_visible_range,
 4260                    ),
 4261                ))
 4262            })
 4263            .collect()
 4264    }
 4265
 4266    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
 4267        TextLayoutDetails {
 4268            text_system: cx.text_system().clone(),
 4269            editor_style: self.style.clone().unwrap(),
 4270            rem_size: cx.rem_size(),
 4271            scroll_anchor: self.scroll_manager.anchor(),
 4272            visible_rows: self.visible_line_count(),
 4273            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4274        }
 4275    }
 4276
 4277    fn splice_inlays(
 4278        &self,
 4279        to_remove: Vec<InlayId>,
 4280        to_insert: Vec<Inlay>,
 4281        cx: &mut ViewContext<Self>,
 4282    ) {
 4283        self.display_map.update(cx, |display_map, cx| {
 4284            display_map.splice_inlays(to_remove, to_insert, cx);
 4285        });
 4286        cx.notify();
 4287    }
 4288
 4289    fn trigger_on_type_formatting(
 4290        &self,
 4291        input: String,
 4292        cx: &mut ViewContext<Self>,
 4293    ) -> Option<Task<Result<()>>> {
 4294        if input.len() != 1 {
 4295            return None;
 4296        }
 4297
 4298        let project = self.project.as_ref()?;
 4299        let position = self.selections.newest_anchor().head();
 4300        let (buffer, buffer_position) = self
 4301            .buffer
 4302            .read(cx)
 4303            .text_anchor_for_position(position, cx)?;
 4304
 4305        let settings = language_settings::language_settings(
 4306            buffer
 4307                .read(cx)
 4308                .language_at(buffer_position)
 4309                .map(|l| l.name()),
 4310            buffer.read(cx).file(),
 4311            cx,
 4312        );
 4313        if !settings.use_on_type_format {
 4314            return None;
 4315        }
 4316
 4317        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4318        // hence we do LSP request & edit on host side only — add formats to host's history.
 4319        let push_to_lsp_host_history = true;
 4320        // If this is not the host, append its history with new edits.
 4321        let push_to_client_history = project.read(cx).is_via_collab();
 4322
 4323        let on_type_formatting = project.update(cx, |project, cx| {
 4324            project.on_type_format(
 4325                buffer.clone(),
 4326                buffer_position,
 4327                input,
 4328                push_to_lsp_host_history,
 4329                cx,
 4330            )
 4331        });
 4332        Some(cx.spawn(|editor, mut cx| async move {
 4333            if let Some(transaction) = on_type_formatting.await? {
 4334                if push_to_client_history {
 4335                    buffer
 4336                        .update(&mut cx, |buffer, _| {
 4337                            buffer.push_transaction(transaction, Instant::now());
 4338                        })
 4339                        .ok();
 4340                }
 4341                editor.update(&mut cx, |editor, cx| {
 4342                    editor.refresh_document_highlights(cx);
 4343                })?;
 4344            }
 4345            Ok(())
 4346        }))
 4347    }
 4348
 4349    pub fn show_completions(&mut self, options: &ShowCompletions, cx: &mut ViewContext<Self>) {
 4350        if self.pending_rename.is_some() {
 4351            return;
 4352        }
 4353
 4354        let Some(provider) = self.completion_provider.as_ref() else {
 4355            return;
 4356        };
 4357
 4358        let position = self.selections.newest_anchor().head();
 4359        let (buffer, buffer_position) =
 4360            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4361                output
 4362            } else {
 4363                return;
 4364            };
 4365
 4366        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4367        let is_followup_invoke = {
 4368            let context_menu_state = self.context_menu.read();
 4369            matches!(
 4370                context_menu_state.deref(),
 4371                Some(ContextMenu::Completions(_))
 4372            )
 4373        };
 4374        let trigger_kind = match (&options.trigger, is_followup_invoke) {
 4375            (_, true) => CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS,
 4376            (Some(trigger), _) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4377                CompletionTriggerKind::TRIGGER_CHARACTER
 4378            }
 4379
 4380            _ => CompletionTriggerKind::INVOKED,
 4381        };
 4382        let completion_context = CompletionContext {
 4383            trigger_character: options.trigger.as_ref().and_then(|trigger| {
 4384                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4385                    Some(String::from(trigger))
 4386                } else {
 4387                    None
 4388                }
 4389            }),
 4390            trigger_kind,
 4391        };
 4392        let completions = provider.completions(&buffer, buffer_position, completion_context, cx);
 4393        let sort_completions = provider.sort_completions();
 4394
 4395        let id = post_inc(&mut self.next_completion_id);
 4396        let task = cx.spawn(|this, mut cx| {
 4397            async move {
 4398                this.update(&mut cx, |this, _| {
 4399                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4400                })?;
 4401                let completions = completions.await.log_err();
 4402                let menu = if let Some(completions) = completions {
 4403                    let mut menu = CompletionsMenu {
 4404                        id,
 4405                        sort_completions,
 4406                        initial_position: position,
 4407                        match_candidates: completions
 4408                            .iter()
 4409                            .enumerate()
 4410                            .map(|(id, completion)| {
 4411                                StringMatchCandidate::new(
 4412                                    id,
 4413                                    completion.label.text[completion.label.filter_range.clone()]
 4414                                        .into(),
 4415                                )
 4416                            })
 4417                            .collect(),
 4418                        buffer: buffer.clone(),
 4419                        completions: Arc::new(RwLock::new(completions.into())),
 4420                        matches: Vec::new().into(),
 4421                        selected_item: 0,
 4422                        scroll_handle: UniformListScrollHandle::new(),
 4423                        selected_completion_documentation_resolve_debounce: Arc::new(Mutex::new(
 4424                            DebouncedDelay::new(),
 4425                        )),
 4426                    };
 4427                    menu.filter(query.as_deref(), cx.background_executor().clone())
 4428                        .await;
 4429
 4430                    if menu.matches.is_empty() {
 4431                        None
 4432                    } else {
 4433                        this.update(&mut cx, |editor, cx| {
 4434                            let completions = menu.completions.clone();
 4435                            let matches = menu.matches.clone();
 4436
 4437                            let delay_ms = EditorSettings::get_global(cx)
 4438                                .completion_documentation_secondary_query_debounce;
 4439                            let delay = Duration::from_millis(delay_ms);
 4440                            editor
 4441                                .completion_documentation_pre_resolve_debounce
 4442                                .fire_new(delay, cx, |editor, cx| {
 4443                                    CompletionsMenu::pre_resolve_completion_documentation(
 4444                                        buffer,
 4445                                        completions,
 4446                                        matches,
 4447                                        editor,
 4448                                        cx,
 4449                                    )
 4450                                });
 4451                        })
 4452                        .ok();
 4453                        Some(menu)
 4454                    }
 4455                } else {
 4456                    None
 4457                };
 4458
 4459                this.update(&mut cx, |this, cx| {
 4460                    let mut context_menu = this.context_menu.write();
 4461                    match context_menu.as_ref() {
 4462                        None => {}
 4463
 4464                        Some(ContextMenu::Completions(prev_menu)) => {
 4465                            if prev_menu.id > id {
 4466                                return;
 4467                            }
 4468                        }
 4469
 4470                        _ => return,
 4471                    }
 4472
 4473                    if this.focus_handle.is_focused(cx) && menu.is_some() {
 4474                        let menu = menu.unwrap();
 4475                        *context_menu = Some(ContextMenu::Completions(menu));
 4476                        drop(context_menu);
 4477                        this.discard_inline_completion(false, cx);
 4478                        cx.notify();
 4479                    } else if this.completion_tasks.len() <= 1 {
 4480                        // If there are no more completion tasks and the last menu was
 4481                        // empty, we should hide it. If it was already hidden, we should
 4482                        // also show the copilot completion when available.
 4483                        drop(context_menu);
 4484                        if this.hide_context_menu(cx).is_none() {
 4485                            this.update_visible_inline_completion(cx);
 4486                        }
 4487                    }
 4488                })?;
 4489
 4490                Ok::<_, anyhow::Error>(())
 4491            }
 4492            .log_err()
 4493        });
 4494
 4495        self.completion_tasks.push((id, task));
 4496    }
 4497
 4498    pub fn confirm_completion(
 4499        &mut self,
 4500        action: &ConfirmCompletion,
 4501        cx: &mut ViewContext<Self>,
 4502    ) -> Option<Task<Result<()>>> {
 4503        self.do_completion(action.item_ix, CompletionIntent::Complete, cx)
 4504    }
 4505
 4506    pub fn compose_completion(
 4507        &mut self,
 4508        action: &ComposeCompletion,
 4509        cx: &mut ViewContext<Self>,
 4510    ) -> Option<Task<Result<()>>> {
 4511        self.do_completion(action.item_ix, CompletionIntent::Compose, cx)
 4512    }
 4513
 4514    fn do_completion(
 4515        &mut self,
 4516        item_ix: Option<usize>,
 4517        intent: CompletionIntent,
 4518        cx: &mut ViewContext<Editor>,
 4519    ) -> Option<Task<std::result::Result<(), anyhow::Error>>> {
 4520        use language::ToOffset as _;
 4521
 4522        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
 4523            menu
 4524        } else {
 4525            return None;
 4526        };
 4527
 4528        let mat = completions_menu
 4529            .matches
 4530            .get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4531        let buffer_handle = completions_menu.buffer;
 4532        let completions = completions_menu.completions.read();
 4533        let completion = completions.get(mat.candidate_id)?;
 4534        cx.stop_propagation();
 4535
 4536        let snippet;
 4537        let text;
 4538
 4539        if completion.is_snippet() {
 4540            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4541            text = snippet.as_ref().unwrap().text.clone();
 4542        } else {
 4543            snippet = None;
 4544            text = completion.new_text.clone();
 4545        };
 4546        let selections = self.selections.all::<usize>(cx);
 4547        let buffer = buffer_handle.read(cx);
 4548        let old_range = completion.old_range.to_offset(buffer);
 4549        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 4550
 4551        let newest_selection = self.selections.newest_anchor();
 4552        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
 4553            return None;
 4554        }
 4555
 4556        let lookbehind = newest_selection
 4557            .start
 4558            .text_anchor
 4559            .to_offset(buffer)
 4560            .saturating_sub(old_range.start);
 4561        let lookahead = old_range
 4562            .end
 4563            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 4564        let mut common_prefix_len = old_text
 4565            .bytes()
 4566            .zip(text.bytes())
 4567            .take_while(|(a, b)| a == b)
 4568            .count();
 4569
 4570        let snapshot = self.buffer.read(cx).snapshot(cx);
 4571        let mut range_to_replace: Option<Range<isize>> = None;
 4572        let mut ranges = Vec::new();
 4573        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4574        for selection in &selections {
 4575            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 4576                let start = selection.start.saturating_sub(lookbehind);
 4577                let end = selection.end + lookahead;
 4578                if selection.id == newest_selection.id {
 4579                    range_to_replace = Some(
 4580                        ((start + common_prefix_len) as isize - selection.start as isize)
 4581                            ..(end as isize - selection.start as isize),
 4582                    );
 4583                }
 4584                ranges.push(start + common_prefix_len..end);
 4585            } else {
 4586                common_prefix_len = 0;
 4587                ranges.clear();
 4588                ranges.extend(selections.iter().map(|s| {
 4589                    if s.id == newest_selection.id {
 4590                        range_to_replace = Some(
 4591                            old_range.start.to_offset_utf16(&snapshot).0 as isize
 4592                                - selection.start as isize
 4593                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
 4594                                    - selection.start as isize,
 4595                        );
 4596                        old_range.clone()
 4597                    } else {
 4598                        s.start..s.end
 4599                    }
 4600                }));
 4601                break;
 4602            }
 4603            if !self.linked_edit_ranges.is_empty() {
 4604                let start_anchor = snapshot.anchor_before(selection.head());
 4605                let end_anchor = snapshot.anchor_after(selection.tail());
 4606                if let Some(ranges) = self
 4607                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4608                {
 4609                    for (buffer, edits) in ranges {
 4610                        linked_edits.entry(buffer.clone()).or_default().extend(
 4611                            edits
 4612                                .into_iter()
 4613                                .map(|range| (range, text[common_prefix_len..].to_owned())),
 4614                        );
 4615                    }
 4616                }
 4617            }
 4618        }
 4619        let text = &text[common_prefix_len..];
 4620
 4621        cx.emit(EditorEvent::InputHandled {
 4622            utf16_range_to_replace: range_to_replace,
 4623            text: text.into(),
 4624        });
 4625
 4626        self.transact(cx, |this, cx| {
 4627            if let Some(mut snippet) = snippet {
 4628                snippet.text = text.to_string();
 4629                for tabstop in snippet.tabstops.iter_mut().flatten() {
 4630                    tabstop.start -= common_prefix_len as isize;
 4631                    tabstop.end -= common_prefix_len as isize;
 4632                }
 4633
 4634                this.insert_snippet(&ranges, snippet, cx).log_err();
 4635            } else {
 4636                this.buffer.update(cx, |buffer, cx| {
 4637                    buffer.edit(
 4638                        ranges.iter().map(|range| (range.clone(), text)),
 4639                        this.autoindent_mode.clone(),
 4640                        cx,
 4641                    );
 4642                });
 4643            }
 4644            for (buffer, edits) in linked_edits {
 4645                buffer.update(cx, |buffer, cx| {
 4646                    let snapshot = buffer.snapshot();
 4647                    let edits = edits
 4648                        .into_iter()
 4649                        .map(|(range, text)| {
 4650                            use text::ToPoint as TP;
 4651                            let end_point = TP::to_point(&range.end, &snapshot);
 4652                            let start_point = TP::to_point(&range.start, &snapshot);
 4653                            (start_point..end_point, text)
 4654                        })
 4655                        .sorted_by_key(|(range, _)| range.start)
 4656                        .collect::<Vec<_>>();
 4657                    buffer.edit(edits, None, cx);
 4658                })
 4659            }
 4660
 4661            this.refresh_inline_completion(true, false, cx);
 4662        });
 4663
 4664        let show_new_completions_on_confirm = completion
 4665            .confirm
 4666            .as_ref()
 4667            .map_or(false, |confirm| confirm(intent, cx));
 4668        if show_new_completions_on_confirm {
 4669            self.show_completions(&ShowCompletions { trigger: None }, cx);
 4670        }
 4671
 4672        let provider = self.completion_provider.as_ref()?;
 4673        let apply_edits = provider.apply_additional_edits_for_completion(
 4674            buffer_handle,
 4675            completion.clone(),
 4676            true,
 4677            cx,
 4678        );
 4679
 4680        let editor_settings = EditorSettings::get_global(cx);
 4681        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 4682            // After the code completion is finished, users often want to know what signatures are needed.
 4683            // so we should automatically call signature_help
 4684            self.show_signature_help(&ShowSignatureHelp, cx);
 4685        }
 4686
 4687        Some(cx.foreground_executor().spawn(async move {
 4688            apply_edits.await?;
 4689            Ok(())
 4690        }))
 4691    }
 4692
 4693    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
 4694        let mut context_menu = self.context_menu.write();
 4695        if let Some(ContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 4696            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 4697                // Toggle if we're selecting the same one
 4698                *context_menu = None;
 4699                cx.notify();
 4700                return;
 4701            } else {
 4702                // Otherwise, clear it and start a new one
 4703                *context_menu = None;
 4704                cx.notify();
 4705            }
 4706        }
 4707        drop(context_menu);
 4708        let snapshot = self.snapshot(cx);
 4709        let deployed_from_indicator = action.deployed_from_indicator;
 4710        let mut task = self.code_actions_task.take();
 4711        let action = action.clone();
 4712        cx.spawn(|editor, mut cx| async move {
 4713            while let Some(prev_task) = task {
 4714                prev_task.await.log_err();
 4715                task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?;
 4716            }
 4717
 4718            let spawned_test_task = editor.update(&mut cx, |editor, cx| {
 4719                if editor.focus_handle.is_focused(cx) {
 4720                    let multibuffer_point = action
 4721                        .deployed_from_indicator
 4722                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4723                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 4724                    let (buffer, buffer_row) = snapshot
 4725                        .buffer_snapshot
 4726                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4727                        .and_then(|(buffer_snapshot, range)| {
 4728                            editor
 4729                                .buffer
 4730                                .read(cx)
 4731                                .buffer(buffer_snapshot.remote_id())
 4732                                .map(|buffer| (buffer, range.start.row))
 4733                        })?;
 4734                    let (_, code_actions) = editor
 4735                        .available_code_actions
 4736                        .clone()
 4737                        .and_then(|(location, code_actions)| {
 4738                            let snapshot = location.buffer.read(cx).snapshot();
 4739                            let point_range = location.range.to_point(&snapshot);
 4740                            let point_range = point_range.start.row..=point_range.end.row;
 4741                            if point_range.contains(&buffer_row) {
 4742                                Some((location, code_actions))
 4743                            } else {
 4744                                None
 4745                            }
 4746                        })
 4747                        .unzip();
 4748                    let buffer_id = buffer.read(cx).remote_id();
 4749                    let tasks = editor
 4750                        .tasks
 4751                        .get(&(buffer_id, buffer_row))
 4752                        .map(|t| Arc::new(t.to_owned()));
 4753                    if tasks.is_none() && code_actions.is_none() {
 4754                        return None;
 4755                    }
 4756
 4757                    editor.completion_tasks.clear();
 4758                    editor.discard_inline_completion(false, cx);
 4759                    let task_context =
 4760                        tasks
 4761                            .as_ref()
 4762                            .zip(editor.project.clone())
 4763                            .map(|(tasks, project)| {
 4764                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 4765                            });
 4766
 4767                    Some(cx.spawn(|editor, mut cx| async move {
 4768                        let task_context = match task_context {
 4769                            Some(task_context) => task_context.await,
 4770                            None => None,
 4771                        };
 4772                        let resolved_tasks =
 4773                            tasks.zip(task_context).map(|(tasks, task_context)| {
 4774                                Arc::new(ResolvedTasks {
 4775                                    templates: tasks.resolve(&task_context).collect(),
 4776                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 4777                                        multibuffer_point.row,
 4778                                        tasks.column,
 4779                                    )),
 4780                                })
 4781                            });
 4782                        let spawn_straight_away = resolved_tasks
 4783                            .as_ref()
 4784                            .map_or(false, |tasks| tasks.templates.len() == 1)
 4785                            && code_actions
 4786                                .as_ref()
 4787                                .map_or(true, |actions| actions.is_empty());
 4788                        if let Ok(task) = editor.update(&mut cx, |editor, cx| {
 4789                            *editor.context_menu.write() =
 4790                                Some(ContextMenu::CodeActions(CodeActionsMenu {
 4791                                    buffer,
 4792                                    actions: CodeActionContents {
 4793                                        tasks: resolved_tasks,
 4794                                        actions: code_actions,
 4795                                    },
 4796                                    selected_item: Default::default(),
 4797                                    scroll_handle: UniformListScrollHandle::default(),
 4798                                    deployed_from_indicator,
 4799                                }));
 4800                            if spawn_straight_away {
 4801                                if let Some(task) = editor.confirm_code_action(
 4802                                    &ConfirmCodeAction { item_ix: Some(0) },
 4803                                    cx,
 4804                                ) {
 4805                                    cx.notify();
 4806                                    return task;
 4807                                }
 4808                            }
 4809                            cx.notify();
 4810                            Task::ready(Ok(()))
 4811                        }) {
 4812                            task.await
 4813                        } else {
 4814                            Ok(())
 4815                        }
 4816                    }))
 4817                } else {
 4818                    Some(Task::ready(Ok(())))
 4819                }
 4820            })?;
 4821            if let Some(task) = spawned_test_task {
 4822                task.await?;
 4823            }
 4824
 4825            Ok::<_, anyhow::Error>(())
 4826        })
 4827        .detach_and_log_err(cx);
 4828    }
 4829
 4830    pub fn confirm_code_action(
 4831        &mut self,
 4832        action: &ConfirmCodeAction,
 4833        cx: &mut ViewContext<Self>,
 4834    ) -> Option<Task<Result<()>>> {
 4835        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
 4836            menu
 4837        } else {
 4838            return None;
 4839        };
 4840        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 4841        let action = actions_menu.actions.get(action_ix)?;
 4842        let title = action.label();
 4843        let buffer = actions_menu.buffer;
 4844        let workspace = self.workspace()?;
 4845
 4846        match action {
 4847            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 4848                workspace.update(cx, |workspace, cx| {
 4849                    workspace::tasks::schedule_resolved_task(
 4850                        workspace,
 4851                        task_source_kind,
 4852                        resolved_task,
 4853                        false,
 4854                        cx,
 4855                    );
 4856
 4857                    Some(Task::ready(Ok(())))
 4858                })
 4859            }
 4860            CodeActionsItem::CodeAction {
 4861                excerpt_id,
 4862                action,
 4863                provider,
 4864            } => {
 4865                let apply_code_action =
 4866                    provider.apply_code_action(buffer, action, excerpt_id, true, cx);
 4867                let workspace = workspace.downgrade();
 4868                Some(cx.spawn(|editor, cx| async move {
 4869                    let project_transaction = apply_code_action.await?;
 4870                    Self::open_project_transaction(
 4871                        &editor,
 4872                        workspace,
 4873                        project_transaction,
 4874                        title,
 4875                        cx,
 4876                    )
 4877                    .await
 4878                }))
 4879            }
 4880        }
 4881    }
 4882
 4883    pub async fn open_project_transaction(
 4884        this: &WeakView<Editor>,
 4885        workspace: WeakView<Workspace>,
 4886        transaction: ProjectTransaction,
 4887        title: String,
 4888        mut cx: AsyncWindowContext,
 4889    ) -> Result<()> {
 4890        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 4891        cx.update(|cx| {
 4892            entries.sort_unstable_by_key(|(buffer, _)| {
 4893                buffer.read(cx).file().map(|f| f.path().clone())
 4894            });
 4895        })?;
 4896
 4897        // If the project transaction's edits are all contained within this editor, then
 4898        // avoid opening a new editor to display them.
 4899
 4900        if let Some((buffer, transaction)) = entries.first() {
 4901            if entries.len() == 1 {
 4902                let excerpt = this.update(&mut cx, |editor, cx| {
 4903                    editor
 4904                        .buffer()
 4905                        .read(cx)
 4906                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 4907                })?;
 4908                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 4909                    if excerpted_buffer == *buffer {
 4910                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
 4911                            let excerpt_range = excerpt_range.to_offset(buffer);
 4912                            buffer
 4913                                .edited_ranges_for_transaction::<usize>(transaction)
 4914                                .all(|range| {
 4915                                    excerpt_range.start <= range.start
 4916                                        && excerpt_range.end >= range.end
 4917                                })
 4918                        })?;
 4919
 4920                        if all_edits_within_excerpt {
 4921                            return Ok(());
 4922                        }
 4923                    }
 4924                }
 4925            }
 4926        } else {
 4927            return Ok(());
 4928        }
 4929
 4930        let mut ranges_to_highlight = Vec::new();
 4931        let excerpt_buffer = cx.new_model(|cx| {
 4932            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 4933            for (buffer_handle, transaction) in &entries {
 4934                let buffer = buffer_handle.read(cx);
 4935                ranges_to_highlight.extend(
 4936                    multibuffer.push_excerpts_with_context_lines(
 4937                        buffer_handle.clone(),
 4938                        buffer
 4939                            .edited_ranges_for_transaction::<usize>(transaction)
 4940                            .collect(),
 4941                        DEFAULT_MULTIBUFFER_CONTEXT,
 4942                        cx,
 4943                    ),
 4944                );
 4945            }
 4946            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 4947            multibuffer
 4948        })?;
 4949
 4950        workspace.update(&mut cx, |workspace, cx| {
 4951            let project = workspace.project().clone();
 4952            let editor =
 4953                cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), true, cx));
 4954            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx);
 4955            editor.update(cx, |editor, cx| {
 4956                editor.highlight_background::<Self>(
 4957                    &ranges_to_highlight,
 4958                    |theme| theme.editor_highlighted_line_background,
 4959                    cx,
 4960                );
 4961            });
 4962        })?;
 4963
 4964        Ok(())
 4965    }
 4966
 4967    pub fn clear_code_action_providers(&mut self) {
 4968        self.code_action_providers.clear();
 4969        self.available_code_actions.take();
 4970    }
 4971
 4972    pub fn push_code_action_provider(
 4973        &mut self,
 4974        provider: Arc<dyn CodeActionProvider>,
 4975        cx: &mut ViewContext<Self>,
 4976    ) {
 4977        self.code_action_providers.push(provider);
 4978        self.refresh_code_actions(cx);
 4979    }
 4980
 4981    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 4982        let buffer = self.buffer.read(cx);
 4983        let newest_selection = self.selections.newest_anchor().clone();
 4984        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 4985        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 4986        if start_buffer != end_buffer {
 4987            return None;
 4988        }
 4989
 4990        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
 4991            cx.background_executor()
 4992                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 4993                .await;
 4994
 4995            let (providers, tasks) = this.update(&mut cx, |this, cx| {
 4996                let providers = this.code_action_providers.clone();
 4997                let tasks = this
 4998                    .code_action_providers
 4999                    .iter()
 5000                    .map(|provider| provider.code_actions(&start_buffer, start..end, cx))
 5001                    .collect::<Vec<_>>();
 5002                (providers, tasks)
 5003            })?;
 5004
 5005            let mut actions = Vec::new();
 5006            for (provider, provider_actions) in
 5007                providers.into_iter().zip(future::join_all(tasks).await)
 5008            {
 5009                if let Some(provider_actions) = provider_actions.log_err() {
 5010                    actions.extend(provider_actions.into_iter().map(|action| {
 5011                        AvailableCodeAction {
 5012                            excerpt_id: newest_selection.start.excerpt_id,
 5013                            action,
 5014                            provider: provider.clone(),
 5015                        }
 5016                    }));
 5017                }
 5018            }
 5019
 5020            this.update(&mut cx, |this, cx| {
 5021                this.available_code_actions = if actions.is_empty() {
 5022                    None
 5023                } else {
 5024                    Some((
 5025                        Location {
 5026                            buffer: start_buffer,
 5027                            range: start..end,
 5028                        },
 5029                        actions.into(),
 5030                    ))
 5031                };
 5032                cx.notify();
 5033            })
 5034        }));
 5035        None
 5036    }
 5037
 5038    fn start_inline_blame_timer(&mut self, cx: &mut ViewContext<Self>) {
 5039        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5040            self.show_git_blame_inline = false;
 5041
 5042            self.show_git_blame_inline_delay_task = Some(cx.spawn(|this, mut cx| async move {
 5043                cx.background_executor().timer(delay).await;
 5044
 5045                this.update(&mut cx, |this, cx| {
 5046                    this.show_git_blame_inline = true;
 5047                    cx.notify();
 5048                })
 5049                .log_err();
 5050            }));
 5051        }
 5052    }
 5053
 5054    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 5055        if self.pending_rename.is_some() {
 5056            return None;
 5057        }
 5058
 5059        let provider = self.semantics_provider.clone()?;
 5060        let buffer = self.buffer.read(cx);
 5061        let newest_selection = self.selections.newest_anchor().clone();
 5062        let cursor_position = newest_selection.head();
 5063        let (cursor_buffer, cursor_buffer_position) =
 5064            buffer.text_anchor_for_position(cursor_position, cx)?;
 5065        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5066        if cursor_buffer != tail_buffer {
 5067            return None;
 5068        }
 5069
 5070        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
 5071            cx.background_executor()
 5072                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
 5073                .await;
 5074
 5075            let highlights = if let Some(highlights) = cx
 5076                .update(|cx| {
 5077                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5078                })
 5079                .ok()
 5080                .flatten()
 5081            {
 5082                highlights.await.log_err()
 5083            } else {
 5084                None
 5085            };
 5086
 5087            if let Some(highlights) = highlights {
 5088                this.update(&mut cx, |this, cx| {
 5089                    if this.pending_rename.is_some() {
 5090                        return;
 5091                    }
 5092
 5093                    let buffer_id = cursor_position.buffer_id;
 5094                    let buffer = this.buffer.read(cx);
 5095                    if !buffer
 5096                        .text_anchor_for_position(cursor_position, cx)
 5097                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5098                    {
 5099                        return;
 5100                    }
 5101
 5102                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5103                    let mut write_ranges = Vec::new();
 5104                    let mut read_ranges = Vec::new();
 5105                    for highlight in highlights {
 5106                        for (excerpt_id, excerpt_range) in
 5107                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
 5108                        {
 5109                            let start = highlight
 5110                                .range
 5111                                .start
 5112                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5113                            let end = highlight
 5114                                .range
 5115                                .end
 5116                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5117                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5118                                continue;
 5119                            }
 5120
 5121                            let range = Anchor {
 5122                                buffer_id,
 5123                                excerpt_id,
 5124                                text_anchor: start,
 5125                            }..Anchor {
 5126                                buffer_id,
 5127                                excerpt_id,
 5128                                text_anchor: end,
 5129                            };
 5130                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5131                                write_ranges.push(range);
 5132                            } else {
 5133                                read_ranges.push(range);
 5134                            }
 5135                        }
 5136                    }
 5137
 5138                    this.highlight_background::<DocumentHighlightRead>(
 5139                        &read_ranges,
 5140                        |theme| theme.editor_document_highlight_read_background,
 5141                        cx,
 5142                    );
 5143                    this.highlight_background::<DocumentHighlightWrite>(
 5144                        &write_ranges,
 5145                        |theme| theme.editor_document_highlight_write_background,
 5146                        cx,
 5147                    );
 5148                    cx.notify();
 5149                })
 5150                .log_err();
 5151            }
 5152        }));
 5153        None
 5154    }
 5155
 5156    pub fn refresh_inline_completion(
 5157        &mut self,
 5158        debounce: bool,
 5159        user_requested: bool,
 5160        cx: &mut ViewContext<Self>,
 5161    ) -> Option<()> {
 5162        let provider = self.inline_completion_provider()?;
 5163        let cursor = self.selections.newest_anchor().head();
 5164        let (buffer, cursor_buffer_position) =
 5165            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5166
 5167        if !user_requested
 5168            && (!self.enable_inline_completions
 5169                || !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx))
 5170        {
 5171            self.discard_inline_completion(false, cx);
 5172            return None;
 5173        }
 5174
 5175        self.update_visible_inline_completion(cx);
 5176        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 5177        Some(())
 5178    }
 5179
 5180    fn cycle_inline_completion(
 5181        &mut self,
 5182        direction: Direction,
 5183        cx: &mut ViewContext<Self>,
 5184    ) -> Option<()> {
 5185        let provider = self.inline_completion_provider()?;
 5186        let cursor = self.selections.newest_anchor().head();
 5187        let (buffer, cursor_buffer_position) =
 5188            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5189        if !self.enable_inline_completions
 5190            || !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx)
 5191        {
 5192            return None;
 5193        }
 5194
 5195        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 5196        self.update_visible_inline_completion(cx);
 5197
 5198        Some(())
 5199    }
 5200
 5201    pub fn show_inline_completion(&mut self, _: &ShowInlineCompletion, cx: &mut ViewContext<Self>) {
 5202        if !self.has_active_inline_completion(cx) {
 5203            self.refresh_inline_completion(false, true, cx);
 5204            return;
 5205        }
 5206
 5207        self.update_visible_inline_completion(cx);
 5208    }
 5209
 5210    pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext<Self>) {
 5211        self.show_cursor_names(cx);
 5212    }
 5213
 5214    fn show_cursor_names(&mut self, cx: &mut ViewContext<Self>) {
 5215        self.show_cursor_names = true;
 5216        cx.notify();
 5217        cx.spawn(|this, mut cx| async move {
 5218            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 5219            this.update(&mut cx, |this, cx| {
 5220                this.show_cursor_names = false;
 5221                cx.notify()
 5222            })
 5223            .ok()
 5224        })
 5225        .detach();
 5226    }
 5227
 5228    pub fn next_inline_completion(&mut self, _: &NextInlineCompletion, cx: &mut ViewContext<Self>) {
 5229        if self.has_active_inline_completion(cx) {
 5230            self.cycle_inline_completion(Direction::Next, cx);
 5231        } else {
 5232            let is_copilot_disabled = self.refresh_inline_completion(false, true, cx).is_none();
 5233            if is_copilot_disabled {
 5234                cx.propagate();
 5235            }
 5236        }
 5237    }
 5238
 5239    pub fn previous_inline_completion(
 5240        &mut self,
 5241        _: &PreviousInlineCompletion,
 5242        cx: &mut ViewContext<Self>,
 5243    ) {
 5244        if self.has_active_inline_completion(cx) {
 5245            self.cycle_inline_completion(Direction::Prev, cx);
 5246        } else {
 5247            let is_copilot_disabled = self.refresh_inline_completion(false, true, cx).is_none();
 5248            if is_copilot_disabled {
 5249                cx.propagate();
 5250            }
 5251        }
 5252    }
 5253
 5254    pub fn accept_inline_completion(
 5255        &mut self,
 5256        _: &AcceptInlineCompletion,
 5257        cx: &mut ViewContext<Self>,
 5258    ) {
 5259        let Some(completion) = self.take_active_inline_completion(cx) else {
 5260            return;
 5261        };
 5262        if let Some(provider) = self.inline_completion_provider() {
 5263            provider.accept(cx);
 5264        }
 5265
 5266        cx.emit(EditorEvent::InputHandled {
 5267            utf16_range_to_replace: None,
 5268            text: completion.text.to_string().into(),
 5269        });
 5270
 5271        if let Some(range) = completion.delete_range {
 5272            self.change_selections(None, cx, |s| s.select_ranges([range]))
 5273        }
 5274        self.insert_with_autoindent_mode(&completion.text.to_string(), None, cx);
 5275        self.refresh_inline_completion(true, true, cx);
 5276        cx.notify();
 5277    }
 5278
 5279    pub fn accept_partial_inline_completion(
 5280        &mut self,
 5281        _: &AcceptPartialInlineCompletion,
 5282        cx: &mut ViewContext<Self>,
 5283    ) {
 5284        if self.selections.count() == 1 && self.has_active_inline_completion(cx) {
 5285            if let Some(completion) = self.take_active_inline_completion(cx) {
 5286                let mut partial_completion = completion
 5287                    .text
 5288                    .chars()
 5289                    .by_ref()
 5290                    .take_while(|c| c.is_alphabetic())
 5291                    .collect::<String>();
 5292                if partial_completion.is_empty() {
 5293                    partial_completion = completion
 5294                        .text
 5295                        .chars()
 5296                        .by_ref()
 5297                        .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 5298                        .collect::<String>();
 5299                }
 5300
 5301                cx.emit(EditorEvent::InputHandled {
 5302                    utf16_range_to_replace: None,
 5303                    text: partial_completion.clone().into(),
 5304                });
 5305
 5306                if let Some(range) = completion.delete_range {
 5307                    self.change_selections(None, cx, |s| s.select_ranges([range]))
 5308                }
 5309                self.insert_with_autoindent_mode(&partial_completion, None, cx);
 5310
 5311                self.refresh_inline_completion(true, true, cx);
 5312                cx.notify();
 5313            }
 5314        }
 5315    }
 5316
 5317    fn discard_inline_completion(
 5318        &mut self,
 5319        should_report_inline_completion_event: bool,
 5320        cx: &mut ViewContext<Self>,
 5321    ) -> bool {
 5322        if let Some(provider) = self.inline_completion_provider() {
 5323            provider.discard(should_report_inline_completion_event, cx);
 5324        }
 5325
 5326        self.take_active_inline_completion(cx).is_some()
 5327    }
 5328
 5329    pub fn has_active_inline_completion(&self, cx: &AppContext) -> bool {
 5330        if let Some(completion) = self.active_inline_completion.as_ref() {
 5331            let buffer = self.buffer.read(cx).read(cx);
 5332            completion.position.is_valid(&buffer)
 5333        } else {
 5334            false
 5335        }
 5336    }
 5337
 5338    fn take_active_inline_completion(
 5339        &mut self,
 5340        cx: &mut ViewContext<Self>,
 5341    ) -> Option<CompletionState> {
 5342        let completion = self.active_inline_completion.take()?;
 5343        let render_inlay_ids = completion.render_inlay_ids.clone();
 5344        self.display_map.update(cx, |map, cx| {
 5345            map.splice_inlays(render_inlay_ids, Default::default(), cx);
 5346        });
 5347        let buffer = self.buffer.read(cx).read(cx);
 5348
 5349        if completion.position.is_valid(&buffer) {
 5350            Some(completion)
 5351        } else {
 5352            None
 5353        }
 5354    }
 5355
 5356    fn update_visible_inline_completion(&mut self, cx: &mut ViewContext<Self>) {
 5357        let selection = self.selections.newest_anchor();
 5358        let cursor = selection.head();
 5359
 5360        let excerpt_id = cursor.excerpt_id;
 5361
 5362        if self.context_menu.read().is_none()
 5363            && self.completion_tasks.is_empty()
 5364            && selection.start == selection.end
 5365        {
 5366            if let Some(provider) = self.inline_completion_provider() {
 5367                if let Some((buffer, cursor_buffer_position)) =
 5368                    self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5369                {
 5370                    if let Some(proposal) =
 5371                        provider.active_completion_text(&buffer, cursor_buffer_position, cx)
 5372                    {
 5373                        let mut to_remove = Vec::new();
 5374                        if let Some(completion) = self.active_inline_completion.take() {
 5375                            to_remove.extend(completion.render_inlay_ids.iter());
 5376                        }
 5377
 5378                        let to_add = proposal
 5379                            .inlays
 5380                            .iter()
 5381                            .filter_map(|inlay| {
 5382                                let snapshot = self.buffer.read(cx).snapshot(cx);
 5383                                let id = post_inc(&mut self.next_inlay_id);
 5384                                match inlay {
 5385                                    InlayProposal::Hint(position, hint) => {
 5386                                        let position =
 5387                                            snapshot.anchor_in_excerpt(excerpt_id, *position)?;
 5388                                        Some(Inlay::hint(id, position, hint))
 5389                                    }
 5390                                    InlayProposal::Suggestion(position, text) => {
 5391                                        let position =
 5392                                            snapshot.anchor_in_excerpt(excerpt_id, *position)?;
 5393                                        Some(Inlay::suggestion(id, position, text.clone()))
 5394                                    }
 5395                                }
 5396                            })
 5397                            .collect_vec();
 5398
 5399                        self.active_inline_completion = Some(CompletionState {
 5400                            position: cursor,
 5401                            text: proposal.text,
 5402                            delete_range: proposal.delete_range.and_then(|range| {
 5403                                let snapshot = self.buffer.read(cx).snapshot(cx);
 5404                                let start = snapshot.anchor_in_excerpt(excerpt_id, range.start);
 5405                                let end = snapshot.anchor_in_excerpt(excerpt_id, range.end);
 5406                                Some(start?..end?)
 5407                            }),
 5408                            render_inlay_ids: to_add.iter().map(|i| i.id).collect(),
 5409                        });
 5410
 5411                        self.display_map
 5412                            .update(cx, move |map, cx| map.splice_inlays(to_remove, to_add, cx));
 5413
 5414                        cx.notify();
 5415                        return;
 5416                    }
 5417                }
 5418            }
 5419        }
 5420
 5421        self.discard_inline_completion(false, cx);
 5422    }
 5423
 5424    fn inline_completion_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 5425        Some(self.inline_completion_provider.as_ref()?.provider.clone())
 5426    }
 5427
 5428    fn render_code_actions_indicator(
 5429        &self,
 5430        _style: &EditorStyle,
 5431        row: DisplayRow,
 5432        is_active: bool,
 5433        cx: &mut ViewContext<Self>,
 5434    ) -> Option<IconButton> {
 5435        if self.available_code_actions.is_some() {
 5436            Some(
 5437                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 5438                    .shape(ui::IconButtonShape::Square)
 5439                    .icon_size(IconSize::XSmall)
 5440                    .icon_color(Color::Muted)
 5441                    .selected(is_active)
 5442                    .tooltip({
 5443                        let focus_handle = self.focus_handle.clone();
 5444                        move |cx| {
 5445                            Tooltip::for_action_in(
 5446                                "Toggle Code Actions",
 5447                                &ToggleCodeActions {
 5448                                    deployed_from_indicator: None,
 5449                                },
 5450                                &focus_handle,
 5451                                cx,
 5452                            )
 5453                        }
 5454                    })
 5455                    .on_click(cx.listener(move |editor, _e, cx| {
 5456                        editor.focus(cx);
 5457                        editor.toggle_code_actions(
 5458                            &ToggleCodeActions {
 5459                                deployed_from_indicator: Some(row),
 5460                            },
 5461                            cx,
 5462                        );
 5463                    })),
 5464            )
 5465        } else {
 5466            None
 5467        }
 5468    }
 5469
 5470    fn clear_tasks(&mut self) {
 5471        self.tasks.clear()
 5472    }
 5473
 5474    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 5475        if self.tasks.insert(key, value).is_some() {
 5476            // This case should hopefully be rare, but just in case...
 5477            log::error!("multiple different run targets found on a single line, only the last target will be rendered")
 5478        }
 5479    }
 5480
 5481    fn build_tasks_context(
 5482        project: &Model<Project>,
 5483        buffer: &Model<Buffer>,
 5484        buffer_row: u32,
 5485        tasks: &Arc<RunnableTasks>,
 5486        cx: &mut ViewContext<Self>,
 5487    ) -> Task<Option<task::TaskContext>> {
 5488        let position = Point::new(buffer_row, tasks.column);
 5489        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 5490        let location = Location {
 5491            buffer: buffer.clone(),
 5492            range: range_start..range_start,
 5493        };
 5494        // Fill in the environmental variables from the tree-sitter captures
 5495        let mut captured_task_variables = TaskVariables::default();
 5496        for (capture_name, value) in tasks.extra_variables.clone() {
 5497            captured_task_variables.insert(
 5498                task::VariableName::Custom(capture_name.into()),
 5499                value.clone(),
 5500            );
 5501        }
 5502        project.update(cx, |project, cx| {
 5503            project.task_store().update(cx, |task_store, cx| {
 5504                task_store.task_context_for_location(captured_task_variables, location, cx)
 5505            })
 5506        })
 5507    }
 5508
 5509    pub fn spawn_nearest_task(&mut self, action: &SpawnNearestTask, cx: &mut ViewContext<Self>) {
 5510        let Some((workspace, _)) = self.workspace.clone() else {
 5511            return;
 5512        };
 5513        let Some(project) = self.project.clone() else {
 5514            return;
 5515        };
 5516
 5517        // Try to find a closest, enclosing node using tree-sitter that has a
 5518        // task
 5519        let Some((buffer, buffer_row, tasks)) = self
 5520            .find_enclosing_node_task(cx)
 5521            // Or find the task that's closest in row-distance.
 5522            .or_else(|| self.find_closest_task(cx))
 5523        else {
 5524            return;
 5525        };
 5526
 5527        let reveal_strategy = action.reveal;
 5528        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5529        cx.spawn(|_, mut cx| async move {
 5530            let context = task_context.await?;
 5531            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 5532
 5533            let resolved = resolved_task.resolved.as_mut()?;
 5534            resolved.reveal = reveal_strategy;
 5535
 5536            workspace
 5537                .update(&mut cx, |workspace, cx| {
 5538                    workspace::tasks::schedule_resolved_task(
 5539                        workspace,
 5540                        task_source_kind,
 5541                        resolved_task,
 5542                        false,
 5543                        cx,
 5544                    );
 5545                })
 5546                .ok()
 5547        })
 5548        .detach();
 5549    }
 5550
 5551    fn find_closest_task(
 5552        &mut self,
 5553        cx: &mut ViewContext<Self>,
 5554    ) -> Option<(Model<Buffer>, u32, Arc<RunnableTasks>)> {
 5555        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 5556
 5557        let ((buffer_id, row), tasks) = self
 5558            .tasks
 5559            .iter()
 5560            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 5561
 5562        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 5563        let tasks = Arc::new(tasks.to_owned());
 5564        Some((buffer, *row, tasks))
 5565    }
 5566
 5567    fn find_enclosing_node_task(
 5568        &mut self,
 5569        cx: &mut ViewContext<Self>,
 5570    ) -> Option<(Model<Buffer>, u32, Arc<RunnableTasks>)> {
 5571        let snapshot = self.buffer.read(cx).snapshot(cx);
 5572        let offset = self.selections.newest::<usize>(cx).head();
 5573        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 5574        let buffer_id = excerpt.buffer().remote_id();
 5575
 5576        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 5577        let mut cursor = layer.node().walk();
 5578
 5579        while cursor.goto_first_child_for_byte(offset).is_some() {
 5580            if cursor.node().end_byte() == offset {
 5581                cursor.goto_next_sibling();
 5582            }
 5583        }
 5584
 5585        // Ascend to the smallest ancestor that contains the range and has a task.
 5586        loop {
 5587            let node = cursor.node();
 5588            let node_range = node.byte_range();
 5589            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 5590
 5591            // Check if this node contains our offset
 5592            if node_range.start <= offset && node_range.end >= offset {
 5593                // If it contains offset, check for task
 5594                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 5595                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 5596                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 5597                }
 5598            }
 5599
 5600            if !cursor.goto_parent() {
 5601                break;
 5602            }
 5603        }
 5604        None
 5605    }
 5606
 5607    fn render_run_indicator(
 5608        &self,
 5609        _style: &EditorStyle,
 5610        is_active: bool,
 5611        row: DisplayRow,
 5612        cx: &mut ViewContext<Self>,
 5613    ) -> IconButton {
 5614        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 5615            .shape(ui::IconButtonShape::Square)
 5616            .icon_size(IconSize::XSmall)
 5617            .icon_color(Color::Muted)
 5618            .selected(is_active)
 5619            .on_click(cx.listener(move |editor, _e, cx| {
 5620                editor.focus(cx);
 5621                editor.toggle_code_actions(
 5622                    &ToggleCodeActions {
 5623                        deployed_from_indicator: Some(row),
 5624                    },
 5625                    cx,
 5626                );
 5627            }))
 5628    }
 5629
 5630    pub fn context_menu_visible(&self) -> bool {
 5631        self.context_menu
 5632            .read()
 5633            .as_ref()
 5634            .map_or(false, |menu| menu.visible())
 5635    }
 5636
 5637    fn render_context_menu(
 5638        &self,
 5639        cursor_position: DisplayPoint,
 5640        style: &EditorStyle,
 5641        max_height: Pixels,
 5642        cx: &mut ViewContext<Editor>,
 5643    ) -> Option<(ContextMenuOrigin, AnyElement)> {
 5644        self.context_menu.read().as_ref().map(|menu| {
 5645            menu.render(
 5646                cursor_position,
 5647                style,
 5648                max_height,
 5649                self.workspace.as_ref().map(|(w, _)| w.clone()),
 5650                cx,
 5651            )
 5652        })
 5653    }
 5654
 5655    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
 5656        cx.notify();
 5657        self.completion_tasks.clear();
 5658        let context_menu = self.context_menu.write().take();
 5659        if context_menu.is_some() {
 5660            self.update_visible_inline_completion(cx);
 5661        }
 5662        context_menu
 5663    }
 5664
 5665    pub fn insert_snippet(
 5666        &mut self,
 5667        insertion_ranges: &[Range<usize>],
 5668        snippet: Snippet,
 5669        cx: &mut ViewContext<Self>,
 5670    ) -> Result<()> {
 5671        struct Tabstop<T> {
 5672            is_end_tabstop: bool,
 5673            ranges: Vec<Range<T>>,
 5674        }
 5675
 5676        let tabstops = self.buffer.update(cx, |buffer, cx| {
 5677            let snippet_text: Arc<str> = snippet.text.clone().into();
 5678            buffer.edit(
 5679                insertion_ranges
 5680                    .iter()
 5681                    .cloned()
 5682                    .map(|range| (range, snippet_text.clone())),
 5683                Some(AutoindentMode::EachLine),
 5684                cx,
 5685            );
 5686
 5687            let snapshot = &*buffer.read(cx);
 5688            let snippet = &snippet;
 5689            snippet
 5690                .tabstops
 5691                .iter()
 5692                .map(|tabstop| {
 5693                    let is_end_tabstop = tabstop.first().map_or(false, |tabstop| {
 5694                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 5695                    });
 5696                    let mut tabstop_ranges = tabstop
 5697                        .iter()
 5698                        .flat_map(|tabstop_range| {
 5699                            let mut delta = 0_isize;
 5700                            insertion_ranges.iter().map(move |insertion_range| {
 5701                                let insertion_start = insertion_range.start as isize + delta;
 5702                                delta +=
 5703                                    snippet.text.len() as isize - insertion_range.len() as isize;
 5704
 5705                                let start = ((insertion_start + tabstop_range.start) as usize)
 5706                                    .min(snapshot.len());
 5707                                let end = ((insertion_start + tabstop_range.end) as usize)
 5708                                    .min(snapshot.len());
 5709                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 5710                            })
 5711                        })
 5712                        .collect::<Vec<_>>();
 5713                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 5714
 5715                    Tabstop {
 5716                        is_end_tabstop,
 5717                        ranges: tabstop_ranges,
 5718                    }
 5719                })
 5720                .collect::<Vec<_>>()
 5721        });
 5722        if let Some(tabstop) = tabstops.first() {
 5723            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5724                s.select_ranges(tabstop.ranges.iter().cloned());
 5725            });
 5726
 5727            // If we're already at the last tabstop and it's at the end of the snippet,
 5728            // we're done, we don't need to keep the state around.
 5729            if !tabstop.is_end_tabstop {
 5730                let ranges = tabstops
 5731                    .into_iter()
 5732                    .map(|tabstop| tabstop.ranges)
 5733                    .collect::<Vec<_>>();
 5734                self.snippet_stack.push(SnippetState {
 5735                    active_index: 0,
 5736                    ranges,
 5737                });
 5738            }
 5739
 5740            // Check whether the just-entered snippet ends with an auto-closable bracket.
 5741            if self.autoclose_regions.is_empty() {
 5742                let snapshot = self.buffer.read(cx).snapshot(cx);
 5743                for selection in &mut self.selections.all::<Point>(cx) {
 5744                    let selection_head = selection.head();
 5745                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 5746                        continue;
 5747                    };
 5748
 5749                    let mut bracket_pair = None;
 5750                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 5751                    let prev_chars = snapshot
 5752                        .reversed_chars_at(selection_head)
 5753                        .collect::<String>();
 5754                    for (pair, enabled) in scope.brackets() {
 5755                        if enabled
 5756                            && pair.close
 5757                            && prev_chars.starts_with(pair.start.as_str())
 5758                            && next_chars.starts_with(pair.end.as_str())
 5759                        {
 5760                            bracket_pair = Some(pair.clone());
 5761                            break;
 5762                        }
 5763                    }
 5764                    if let Some(pair) = bracket_pair {
 5765                        let start = snapshot.anchor_after(selection_head);
 5766                        let end = snapshot.anchor_after(selection_head);
 5767                        self.autoclose_regions.push(AutocloseRegion {
 5768                            selection_id: selection.id,
 5769                            range: start..end,
 5770                            pair,
 5771                        });
 5772                    }
 5773                }
 5774            }
 5775        }
 5776        Ok(())
 5777    }
 5778
 5779    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 5780        self.move_to_snippet_tabstop(Bias::Right, cx)
 5781    }
 5782
 5783    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 5784        self.move_to_snippet_tabstop(Bias::Left, cx)
 5785    }
 5786
 5787    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
 5788        if let Some(mut snippet) = self.snippet_stack.pop() {
 5789            match bias {
 5790                Bias::Left => {
 5791                    if snippet.active_index > 0 {
 5792                        snippet.active_index -= 1;
 5793                    } else {
 5794                        self.snippet_stack.push(snippet);
 5795                        return false;
 5796                    }
 5797                }
 5798                Bias::Right => {
 5799                    if snippet.active_index + 1 < snippet.ranges.len() {
 5800                        snippet.active_index += 1;
 5801                    } else {
 5802                        self.snippet_stack.push(snippet);
 5803                        return false;
 5804                    }
 5805                }
 5806            }
 5807            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 5808                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5809                    s.select_anchor_ranges(current_ranges.iter().cloned())
 5810                });
 5811                // If snippet state is not at the last tabstop, push it back on the stack
 5812                if snippet.active_index + 1 < snippet.ranges.len() {
 5813                    self.snippet_stack.push(snippet);
 5814                }
 5815                return true;
 5816            }
 5817        }
 5818
 5819        false
 5820    }
 5821
 5822    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
 5823        self.transact(cx, |this, cx| {
 5824            this.select_all(&SelectAll, cx);
 5825            this.insert("", cx);
 5826        });
 5827    }
 5828
 5829    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
 5830        self.transact(cx, |this, cx| {
 5831            this.select_autoclose_pair(cx);
 5832            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 5833            if !this.linked_edit_ranges.is_empty() {
 5834                let selections = this.selections.all::<MultiBufferPoint>(cx);
 5835                let snapshot = this.buffer.read(cx).snapshot(cx);
 5836
 5837                for selection in selections.iter() {
 5838                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 5839                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 5840                    if selection_start.buffer_id != selection_end.buffer_id {
 5841                        continue;
 5842                    }
 5843                    if let Some(ranges) =
 5844                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 5845                    {
 5846                        for (buffer, entries) in ranges {
 5847                            linked_ranges.entry(buffer).or_default().extend(entries);
 5848                        }
 5849                    }
 5850                }
 5851            }
 5852
 5853            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 5854            if !this.selections.line_mode {
 5855                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5856                for selection in &mut selections {
 5857                    if selection.is_empty() {
 5858                        let old_head = selection.head();
 5859                        let mut new_head =
 5860                            movement::left(&display_map, old_head.to_display_point(&display_map))
 5861                                .to_point(&display_map);
 5862                        if let Some((buffer, line_buffer_range)) = display_map
 5863                            .buffer_snapshot
 5864                            .buffer_line_for_row(MultiBufferRow(old_head.row))
 5865                        {
 5866                            let indent_size =
 5867                                buffer.indent_size_for_line(line_buffer_range.start.row);
 5868                            let indent_len = match indent_size.kind {
 5869                                IndentKind::Space => {
 5870                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
 5871                                }
 5872                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 5873                            };
 5874                            if old_head.column <= indent_size.len && old_head.column > 0 {
 5875                                let indent_len = indent_len.get();
 5876                                new_head = cmp::min(
 5877                                    new_head,
 5878                                    MultiBufferPoint::new(
 5879                                        old_head.row,
 5880                                        ((old_head.column - 1) / indent_len) * indent_len,
 5881                                    ),
 5882                                );
 5883                            }
 5884                        }
 5885
 5886                        selection.set_head(new_head, SelectionGoal::None);
 5887                    }
 5888                }
 5889            }
 5890
 5891            this.signature_help_state.set_backspace_pressed(true);
 5892            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5893            this.insert("", cx);
 5894            let empty_str: Arc<str> = Arc::from("");
 5895            for (buffer, edits) in linked_ranges {
 5896                let snapshot = buffer.read(cx).snapshot();
 5897                use text::ToPoint as TP;
 5898
 5899                let edits = edits
 5900                    .into_iter()
 5901                    .map(|range| {
 5902                        let end_point = TP::to_point(&range.end, &snapshot);
 5903                        let mut start_point = TP::to_point(&range.start, &snapshot);
 5904
 5905                        if end_point == start_point {
 5906                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 5907                                .saturating_sub(1);
 5908                            start_point = TP::to_point(&offset, &snapshot);
 5909                        };
 5910
 5911                        (start_point..end_point, empty_str.clone())
 5912                    })
 5913                    .sorted_by_key(|(range, _)| range.start)
 5914                    .collect::<Vec<_>>();
 5915                buffer.update(cx, |this, cx| {
 5916                    this.edit(edits, None, cx);
 5917                })
 5918            }
 5919            this.refresh_inline_completion(true, false, cx);
 5920            linked_editing_ranges::refresh_linked_ranges(this, cx);
 5921        });
 5922    }
 5923
 5924    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
 5925        self.transact(cx, |this, cx| {
 5926            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5927                let line_mode = s.line_mode;
 5928                s.move_with(|map, selection| {
 5929                    if selection.is_empty() && !line_mode {
 5930                        let cursor = movement::right(map, selection.head());
 5931                        selection.end = cursor;
 5932                        selection.reversed = true;
 5933                        selection.goal = SelectionGoal::None;
 5934                    }
 5935                })
 5936            });
 5937            this.insert("", cx);
 5938            this.refresh_inline_completion(true, false, cx);
 5939        });
 5940    }
 5941
 5942    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
 5943        if self.move_to_prev_snippet_tabstop(cx) {
 5944            return;
 5945        }
 5946
 5947        self.outdent(&Outdent, cx);
 5948    }
 5949
 5950    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
 5951        if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) {
 5952            return;
 5953        }
 5954
 5955        let mut selections = self.selections.all_adjusted(cx);
 5956        let buffer = self.buffer.read(cx);
 5957        let snapshot = buffer.snapshot(cx);
 5958        let rows_iter = selections.iter().map(|s| s.head().row);
 5959        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 5960
 5961        let mut edits = Vec::new();
 5962        let mut prev_edited_row = 0;
 5963        let mut row_delta = 0;
 5964        for selection in &mut selections {
 5965            if selection.start.row != prev_edited_row {
 5966                row_delta = 0;
 5967            }
 5968            prev_edited_row = selection.end.row;
 5969
 5970            // If the selection is non-empty, then increase the indentation of the selected lines.
 5971            if !selection.is_empty() {
 5972                row_delta =
 5973                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 5974                continue;
 5975            }
 5976
 5977            // If the selection is empty and the cursor is in the leading whitespace before the
 5978            // suggested indentation, then auto-indent the line.
 5979            let cursor = selection.head();
 5980            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 5981            if let Some(suggested_indent) =
 5982                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 5983            {
 5984                if cursor.column < suggested_indent.len
 5985                    && cursor.column <= current_indent.len
 5986                    && current_indent.len <= suggested_indent.len
 5987                {
 5988                    selection.start = Point::new(cursor.row, suggested_indent.len);
 5989                    selection.end = selection.start;
 5990                    if row_delta == 0 {
 5991                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 5992                            cursor.row,
 5993                            current_indent,
 5994                            suggested_indent,
 5995                        ));
 5996                        row_delta = suggested_indent.len - current_indent.len;
 5997                    }
 5998                    continue;
 5999                }
 6000            }
 6001
 6002            // Otherwise, insert a hard or soft tab.
 6003            let settings = buffer.settings_at(cursor, cx);
 6004            let tab_size = if settings.hard_tabs {
 6005                IndentSize::tab()
 6006            } else {
 6007                let tab_size = settings.tab_size.get();
 6008                let char_column = snapshot
 6009                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 6010                    .flat_map(str::chars)
 6011                    .count()
 6012                    + row_delta as usize;
 6013                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 6014                IndentSize::spaces(chars_to_next_tab_stop)
 6015            };
 6016            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 6017            selection.end = selection.start;
 6018            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 6019            row_delta += tab_size.len;
 6020        }
 6021
 6022        self.transact(cx, |this, cx| {
 6023            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 6024            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6025            this.refresh_inline_completion(true, false, cx);
 6026        });
 6027    }
 6028
 6029    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
 6030        if self.read_only(cx) {
 6031            return;
 6032        }
 6033        let mut selections = self.selections.all::<Point>(cx);
 6034        let mut prev_edited_row = 0;
 6035        let mut row_delta = 0;
 6036        let mut edits = Vec::new();
 6037        let buffer = self.buffer.read(cx);
 6038        let snapshot = buffer.snapshot(cx);
 6039        for selection in &mut selections {
 6040            if selection.start.row != prev_edited_row {
 6041                row_delta = 0;
 6042            }
 6043            prev_edited_row = selection.end.row;
 6044
 6045            row_delta =
 6046                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 6047        }
 6048
 6049        self.transact(cx, |this, cx| {
 6050            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 6051            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6052        });
 6053    }
 6054
 6055    fn indent_selection(
 6056        buffer: &MultiBuffer,
 6057        snapshot: &MultiBufferSnapshot,
 6058        selection: &mut Selection<Point>,
 6059        edits: &mut Vec<(Range<Point>, String)>,
 6060        delta_for_start_row: u32,
 6061        cx: &AppContext,
 6062    ) -> u32 {
 6063        let settings = buffer.settings_at(selection.start, cx);
 6064        let tab_size = settings.tab_size.get();
 6065        let indent_kind = if settings.hard_tabs {
 6066            IndentKind::Tab
 6067        } else {
 6068            IndentKind::Space
 6069        };
 6070        let mut start_row = selection.start.row;
 6071        let mut end_row = selection.end.row + 1;
 6072
 6073        // If a selection ends at the beginning of a line, don't indent
 6074        // that last line.
 6075        if selection.end.column == 0 && selection.end.row > selection.start.row {
 6076            end_row -= 1;
 6077        }
 6078
 6079        // Avoid re-indenting a row that has already been indented by a
 6080        // previous selection, but still update this selection's column
 6081        // to reflect that indentation.
 6082        if delta_for_start_row > 0 {
 6083            start_row += 1;
 6084            selection.start.column += delta_for_start_row;
 6085            if selection.end.row == selection.start.row {
 6086                selection.end.column += delta_for_start_row;
 6087            }
 6088        }
 6089
 6090        let mut delta_for_end_row = 0;
 6091        let has_multiple_rows = start_row + 1 != end_row;
 6092        for row in start_row..end_row {
 6093            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 6094            let indent_delta = match (current_indent.kind, indent_kind) {
 6095                (IndentKind::Space, IndentKind::Space) => {
 6096                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 6097                    IndentSize::spaces(columns_to_next_tab_stop)
 6098                }
 6099                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 6100                (_, IndentKind::Tab) => IndentSize::tab(),
 6101            };
 6102
 6103            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 6104                0
 6105            } else {
 6106                selection.start.column
 6107            };
 6108            let row_start = Point::new(row, start);
 6109            edits.push((
 6110                row_start..row_start,
 6111                indent_delta.chars().collect::<String>(),
 6112            ));
 6113
 6114            // Update this selection's endpoints to reflect the indentation.
 6115            if row == selection.start.row {
 6116                selection.start.column += indent_delta.len;
 6117            }
 6118            if row == selection.end.row {
 6119                selection.end.column += indent_delta.len;
 6120                delta_for_end_row = indent_delta.len;
 6121            }
 6122        }
 6123
 6124        if selection.start.row == selection.end.row {
 6125            delta_for_start_row + delta_for_end_row
 6126        } else {
 6127            delta_for_end_row
 6128        }
 6129    }
 6130
 6131    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
 6132        if self.read_only(cx) {
 6133            return;
 6134        }
 6135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6136        let selections = self.selections.all::<Point>(cx);
 6137        let mut deletion_ranges = Vec::new();
 6138        let mut last_outdent = None;
 6139        {
 6140            let buffer = self.buffer.read(cx);
 6141            let snapshot = buffer.snapshot(cx);
 6142            for selection in &selections {
 6143                let settings = buffer.settings_at(selection.start, cx);
 6144                let tab_size = settings.tab_size.get();
 6145                let mut rows = selection.spanned_rows(false, &display_map);
 6146
 6147                // Avoid re-outdenting a row that has already been outdented by a
 6148                // previous selection.
 6149                if let Some(last_row) = last_outdent {
 6150                    if last_row == rows.start {
 6151                        rows.start = rows.start.next_row();
 6152                    }
 6153                }
 6154                let has_multiple_rows = rows.len() > 1;
 6155                for row in rows.iter_rows() {
 6156                    let indent_size = snapshot.indent_size_for_line(row);
 6157                    if indent_size.len > 0 {
 6158                        let deletion_len = match indent_size.kind {
 6159                            IndentKind::Space => {
 6160                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 6161                                if columns_to_prev_tab_stop == 0 {
 6162                                    tab_size
 6163                                } else {
 6164                                    columns_to_prev_tab_stop
 6165                                }
 6166                            }
 6167                            IndentKind::Tab => 1,
 6168                        };
 6169                        let start = if has_multiple_rows
 6170                            || deletion_len > selection.start.column
 6171                            || indent_size.len < selection.start.column
 6172                        {
 6173                            0
 6174                        } else {
 6175                            selection.start.column - deletion_len
 6176                        };
 6177                        deletion_ranges.push(
 6178                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 6179                        );
 6180                        last_outdent = Some(row);
 6181                    }
 6182                }
 6183            }
 6184        }
 6185
 6186        self.transact(cx, |this, cx| {
 6187            this.buffer.update(cx, |buffer, cx| {
 6188                let empty_str: Arc<str> = Arc::default();
 6189                buffer.edit(
 6190                    deletion_ranges
 6191                        .into_iter()
 6192                        .map(|range| (range, empty_str.clone())),
 6193                    None,
 6194                    cx,
 6195                );
 6196            });
 6197            let selections = this.selections.all::<usize>(cx);
 6198            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6199        });
 6200    }
 6201
 6202    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
 6203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6204        let selections = self.selections.all::<Point>(cx);
 6205
 6206        let mut new_cursors = Vec::new();
 6207        let mut edit_ranges = Vec::new();
 6208        let mut selections = selections.iter().peekable();
 6209        while let Some(selection) = selections.next() {
 6210            let mut rows = selection.spanned_rows(false, &display_map);
 6211            let goal_display_column = selection.head().to_display_point(&display_map).column();
 6212
 6213            // Accumulate contiguous regions of rows that we want to delete.
 6214            while let Some(next_selection) = selections.peek() {
 6215                let next_rows = next_selection.spanned_rows(false, &display_map);
 6216                if next_rows.start <= rows.end {
 6217                    rows.end = next_rows.end;
 6218                    selections.next().unwrap();
 6219                } else {
 6220                    break;
 6221                }
 6222            }
 6223
 6224            let buffer = &display_map.buffer_snapshot;
 6225            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 6226            let edit_end;
 6227            let cursor_buffer_row;
 6228            if buffer.max_point().row >= rows.end.0 {
 6229                // If there's a line after the range, delete the \n from the end of the row range
 6230                // and position the cursor on the next line.
 6231                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 6232                cursor_buffer_row = rows.end;
 6233            } else {
 6234                // If there isn't a line after the range, delete the \n from the line before the
 6235                // start of the row range and position the cursor there.
 6236                edit_start = edit_start.saturating_sub(1);
 6237                edit_end = buffer.len();
 6238                cursor_buffer_row = rows.start.previous_row();
 6239            }
 6240
 6241            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 6242            *cursor.column_mut() =
 6243                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 6244
 6245            new_cursors.push((
 6246                selection.id,
 6247                buffer.anchor_after(cursor.to_point(&display_map)),
 6248            ));
 6249            edit_ranges.push(edit_start..edit_end);
 6250        }
 6251
 6252        self.transact(cx, |this, cx| {
 6253            let buffer = this.buffer.update(cx, |buffer, cx| {
 6254                let empty_str: Arc<str> = Arc::default();
 6255                buffer.edit(
 6256                    edit_ranges
 6257                        .into_iter()
 6258                        .map(|range| (range, empty_str.clone())),
 6259                    None,
 6260                    cx,
 6261                );
 6262                buffer.snapshot(cx)
 6263            });
 6264            let new_selections = new_cursors
 6265                .into_iter()
 6266                .map(|(id, cursor)| {
 6267                    let cursor = cursor.to_point(&buffer);
 6268                    Selection {
 6269                        id,
 6270                        start: cursor,
 6271                        end: cursor,
 6272                        reversed: false,
 6273                        goal: SelectionGoal::None,
 6274                    }
 6275                })
 6276                .collect();
 6277
 6278            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6279                s.select(new_selections);
 6280            });
 6281        });
 6282    }
 6283
 6284    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
 6285        if self.read_only(cx) {
 6286            return;
 6287        }
 6288        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 6289        for selection in self.selections.all::<Point>(cx) {
 6290            let start = MultiBufferRow(selection.start.row);
 6291            let end = if selection.start.row == selection.end.row {
 6292                MultiBufferRow(selection.start.row + 1)
 6293            } else {
 6294                MultiBufferRow(selection.end.row)
 6295            };
 6296
 6297            if let Some(last_row_range) = row_ranges.last_mut() {
 6298                if start <= last_row_range.end {
 6299                    last_row_range.end = end;
 6300                    continue;
 6301                }
 6302            }
 6303            row_ranges.push(start..end);
 6304        }
 6305
 6306        let snapshot = self.buffer.read(cx).snapshot(cx);
 6307        let mut cursor_positions = Vec::new();
 6308        for row_range in &row_ranges {
 6309            let anchor = snapshot.anchor_before(Point::new(
 6310                row_range.end.previous_row().0,
 6311                snapshot.line_len(row_range.end.previous_row()),
 6312            ));
 6313            cursor_positions.push(anchor..anchor);
 6314        }
 6315
 6316        self.transact(cx, |this, cx| {
 6317            for row_range in row_ranges.into_iter().rev() {
 6318                for row in row_range.iter_rows().rev() {
 6319                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 6320                    let next_line_row = row.next_row();
 6321                    let indent = snapshot.indent_size_for_line(next_line_row);
 6322                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 6323
 6324                    let replace = if snapshot.line_len(next_line_row) > indent.len {
 6325                        " "
 6326                    } else {
 6327                        ""
 6328                    };
 6329
 6330                    this.buffer.update(cx, |buffer, cx| {
 6331                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 6332                    });
 6333                }
 6334            }
 6335
 6336            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6337                s.select_anchor_ranges(cursor_positions)
 6338            });
 6339        });
 6340    }
 6341
 6342    pub fn sort_lines_case_sensitive(
 6343        &mut self,
 6344        _: &SortLinesCaseSensitive,
 6345        cx: &mut ViewContext<Self>,
 6346    ) {
 6347        self.manipulate_lines(cx, |lines| lines.sort())
 6348    }
 6349
 6350    pub fn sort_lines_case_insensitive(
 6351        &mut self,
 6352        _: &SortLinesCaseInsensitive,
 6353        cx: &mut ViewContext<Self>,
 6354    ) {
 6355        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
 6356    }
 6357
 6358    pub fn unique_lines_case_insensitive(
 6359        &mut self,
 6360        _: &UniqueLinesCaseInsensitive,
 6361        cx: &mut ViewContext<Self>,
 6362    ) {
 6363        self.manipulate_lines(cx, |lines| {
 6364            let mut seen = HashSet::default();
 6365            lines.retain(|line| seen.insert(line.to_lowercase()));
 6366        })
 6367    }
 6368
 6369    pub fn unique_lines_case_sensitive(
 6370        &mut self,
 6371        _: &UniqueLinesCaseSensitive,
 6372        cx: &mut ViewContext<Self>,
 6373    ) {
 6374        self.manipulate_lines(cx, |lines| {
 6375            let mut seen = HashSet::default();
 6376            lines.retain(|line| seen.insert(*line));
 6377        })
 6378    }
 6379
 6380    pub fn revert_file(&mut self, _: &RevertFile, cx: &mut ViewContext<Self>) {
 6381        let mut revert_changes = HashMap::default();
 6382        let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6383        for hunk in hunks_for_rows(
 6384            Some(MultiBufferRow(0)..multi_buffer_snapshot.max_buffer_row()).into_iter(),
 6385            &multi_buffer_snapshot,
 6386        ) {
 6387            Self::prepare_revert_change(&mut revert_changes, self.buffer(), &hunk, cx);
 6388        }
 6389        if !revert_changes.is_empty() {
 6390            self.transact(cx, |editor, cx| {
 6391                editor.revert(revert_changes, cx);
 6392            });
 6393        }
 6394    }
 6395
 6396    pub fn reload_file(&mut self, _: &ReloadFile, cx: &mut ViewContext<Self>) {
 6397        let Some(project) = self.project.clone() else {
 6398            return;
 6399        };
 6400        self.reload(project, cx).detach_and_notify_err(cx);
 6401    }
 6402
 6403    pub fn revert_selected_hunks(&mut self, _: &RevertSelectedHunks, cx: &mut ViewContext<Self>) {
 6404        let revert_changes = self.gather_revert_changes(&self.selections.disjoint_anchors(), cx);
 6405        if !revert_changes.is_empty() {
 6406            self.transact(cx, |editor, cx| {
 6407                editor.revert(revert_changes, cx);
 6408            });
 6409        }
 6410    }
 6411
 6412    pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
 6413        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 6414            let project_path = buffer.read(cx).project_path(cx)?;
 6415            let project = self.project.as_ref()?.read(cx);
 6416            let entry = project.entry_for_path(&project_path, cx)?;
 6417            let parent = match &entry.canonical_path {
 6418                Some(canonical_path) => canonical_path.to_path_buf(),
 6419                None => project.absolute_path(&project_path, cx)?,
 6420            }
 6421            .parent()?
 6422            .to_path_buf();
 6423            Some(parent)
 6424        }) {
 6425            cx.dispatch_action(OpenTerminal { working_directory }.boxed_clone());
 6426        }
 6427    }
 6428
 6429    fn gather_revert_changes(
 6430        &mut self,
 6431        selections: &[Selection<Anchor>],
 6432        cx: &mut ViewContext<'_, Editor>,
 6433    ) -> HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>> {
 6434        let mut revert_changes = HashMap::default();
 6435        let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6436        for hunk in hunks_for_selections(&multi_buffer_snapshot, selections) {
 6437            Self::prepare_revert_change(&mut revert_changes, self.buffer(), &hunk, cx);
 6438        }
 6439        revert_changes
 6440    }
 6441
 6442    pub fn prepare_revert_change(
 6443        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 6444        multi_buffer: &Model<MultiBuffer>,
 6445        hunk: &MultiBufferDiffHunk,
 6446        cx: &AppContext,
 6447    ) -> Option<()> {
 6448        let buffer = multi_buffer.read(cx).buffer(hunk.buffer_id)?;
 6449        let buffer = buffer.read(cx);
 6450        let original_text = buffer.diff_base()?.slice(hunk.diff_base_byte_range.clone());
 6451        let buffer_snapshot = buffer.snapshot();
 6452        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 6453        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 6454            probe
 6455                .0
 6456                .start
 6457                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 6458                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 6459        }) {
 6460            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 6461            Some(())
 6462        } else {
 6463            None
 6464        }
 6465    }
 6466
 6467    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
 6468        self.manipulate_lines(cx, |lines| lines.reverse())
 6469    }
 6470
 6471    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
 6472        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
 6473    }
 6474
 6475    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 6476    where
 6477        Fn: FnMut(&mut Vec<&str>),
 6478    {
 6479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6480        let buffer = self.buffer.read(cx).snapshot(cx);
 6481
 6482        let mut edits = Vec::new();
 6483
 6484        let selections = self.selections.all::<Point>(cx);
 6485        let mut selections = selections.iter().peekable();
 6486        let mut contiguous_row_selections = Vec::new();
 6487        let mut new_selections = Vec::new();
 6488        let mut added_lines = 0;
 6489        let mut removed_lines = 0;
 6490
 6491        while let Some(selection) = selections.next() {
 6492            let (start_row, end_row) = consume_contiguous_rows(
 6493                &mut contiguous_row_selections,
 6494                selection,
 6495                &display_map,
 6496                &mut selections,
 6497            );
 6498
 6499            let start_point = Point::new(start_row.0, 0);
 6500            let end_point = Point::new(
 6501                end_row.previous_row().0,
 6502                buffer.line_len(end_row.previous_row()),
 6503            );
 6504            let text = buffer
 6505                .text_for_range(start_point..end_point)
 6506                .collect::<String>();
 6507
 6508            let mut lines = text.split('\n').collect_vec();
 6509
 6510            let lines_before = lines.len();
 6511            callback(&mut lines);
 6512            let lines_after = lines.len();
 6513
 6514            edits.push((start_point..end_point, lines.join("\n")));
 6515
 6516            // Selections must change based on added and removed line count
 6517            let start_row =
 6518                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 6519            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 6520            new_selections.push(Selection {
 6521                id: selection.id,
 6522                start: start_row,
 6523                end: end_row,
 6524                goal: SelectionGoal::None,
 6525                reversed: selection.reversed,
 6526            });
 6527
 6528            if lines_after > lines_before {
 6529                added_lines += lines_after - lines_before;
 6530            } else if lines_before > lines_after {
 6531                removed_lines += lines_before - lines_after;
 6532            }
 6533        }
 6534
 6535        self.transact(cx, |this, cx| {
 6536            let buffer = this.buffer.update(cx, |buffer, cx| {
 6537                buffer.edit(edits, None, cx);
 6538                buffer.snapshot(cx)
 6539            });
 6540
 6541            // Recalculate offsets on newly edited buffer
 6542            let new_selections = new_selections
 6543                .iter()
 6544                .map(|s| {
 6545                    let start_point = Point::new(s.start.0, 0);
 6546                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 6547                    Selection {
 6548                        id: s.id,
 6549                        start: buffer.point_to_offset(start_point),
 6550                        end: buffer.point_to_offset(end_point),
 6551                        goal: s.goal,
 6552                        reversed: s.reversed,
 6553                    }
 6554                })
 6555                .collect();
 6556
 6557            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6558                s.select(new_selections);
 6559            });
 6560
 6561            this.request_autoscroll(Autoscroll::fit(), cx);
 6562        });
 6563    }
 6564
 6565    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
 6566        self.manipulate_text(cx, |text| text.to_uppercase())
 6567    }
 6568
 6569    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
 6570        self.manipulate_text(cx, |text| text.to_lowercase())
 6571    }
 6572
 6573    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
 6574        self.manipulate_text(cx, |text| {
 6575            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 6576            // https://github.com/rutrum/convert-case/issues/16
 6577            text.split('\n')
 6578                .map(|line| line.to_case(Case::Title))
 6579                .join("\n")
 6580        })
 6581    }
 6582
 6583    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
 6584        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
 6585    }
 6586
 6587    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
 6588        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
 6589    }
 6590
 6591    pub fn convert_to_upper_camel_case(
 6592        &mut self,
 6593        _: &ConvertToUpperCamelCase,
 6594        cx: &mut ViewContext<Self>,
 6595    ) {
 6596        self.manipulate_text(cx, |text| {
 6597            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 6598            // https://github.com/rutrum/convert-case/issues/16
 6599            text.split('\n')
 6600                .map(|line| line.to_case(Case::UpperCamel))
 6601                .join("\n")
 6602        })
 6603    }
 6604
 6605    pub fn convert_to_lower_camel_case(
 6606        &mut self,
 6607        _: &ConvertToLowerCamelCase,
 6608        cx: &mut ViewContext<Self>,
 6609    ) {
 6610        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
 6611    }
 6612
 6613    pub fn convert_to_opposite_case(
 6614        &mut self,
 6615        _: &ConvertToOppositeCase,
 6616        cx: &mut ViewContext<Self>,
 6617    ) {
 6618        self.manipulate_text(cx, |text| {
 6619            text.chars()
 6620                .fold(String::with_capacity(text.len()), |mut t, c| {
 6621                    if c.is_uppercase() {
 6622                        t.extend(c.to_lowercase());
 6623                    } else {
 6624                        t.extend(c.to_uppercase());
 6625                    }
 6626                    t
 6627                })
 6628        })
 6629    }
 6630
 6631    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 6632    where
 6633        Fn: FnMut(&str) -> String,
 6634    {
 6635        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6636        let buffer = self.buffer.read(cx).snapshot(cx);
 6637
 6638        let mut new_selections = Vec::new();
 6639        let mut edits = Vec::new();
 6640        let mut selection_adjustment = 0i32;
 6641
 6642        for selection in self.selections.all::<usize>(cx) {
 6643            let selection_is_empty = selection.is_empty();
 6644
 6645            let (start, end) = if selection_is_empty {
 6646                let word_range = movement::surrounding_word(
 6647                    &display_map,
 6648                    selection.start.to_display_point(&display_map),
 6649                );
 6650                let start = word_range.start.to_offset(&display_map, Bias::Left);
 6651                let end = word_range.end.to_offset(&display_map, Bias::Left);
 6652                (start, end)
 6653            } else {
 6654                (selection.start, selection.end)
 6655            };
 6656
 6657            let text = buffer.text_for_range(start..end).collect::<String>();
 6658            let old_length = text.len() as i32;
 6659            let text = callback(&text);
 6660
 6661            new_selections.push(Selection {
 6662                start: (start as i32 - selection_adjustment) as usize,
 6663                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 6664                goal: SelectionGoal::None,
 6665                ..selection
 6666            });
 6667
 6668            selection_adjustment += old_length - text.len() as i32;
 6669
 6670            edits.push((start..end, text));
 6671        }
 6672
 6673        self.transact(cx, |this, cx| {
 6674            this.buffer.update(cx, |buffer, cx| {
 6675                buffer.edit(edits, None, cx);
 6676            });
 6677
 6678            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6679                s.select(new_selections);
 6680            });
 6681
 6682            this.request_autoscroll(Autoscroll::fit(), cx);
 6683        });
 6684    }
 6685
 6686    pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext<Self>) {
 6687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6688        let buffer = &display_map.buffer_snapshot;
 6689        let selections = self.selections.all::<Point>(cx);
 6690
 6691        let mut edits = Vec::new();
 6692        let mut selections_iter = selections.iter().peekable();
 6693        while let Some(selection) = selections_iter.next() {
 6694            // Avoid duplicating the same lines twice.
 6695            let mut rows = selection.spanned_rows(false, &display_map);
 6696
 6697            while let Some(next_selection) = selections_iter.peek() {
 6698                let next_rows = next_selection.spanned_rows(false, &display_map);
 6699                if next_rows.start < rows.end {
 6700                    rows.end = next_rows.end;
 6701                    selections_iter.next().unwrap();
 6702                } else {
 6703                    break;
 6704                }
 6705            }
 6706
 6707            // Copy the text from the selected row region and splice it either at the start
 6708            // or end of the region.
 6709            let start = Point::new(rows.start.0, 0);
 6710            let end = Point::new(
 6711                rows.end.previous_row().0,
 6712                buffer.line_len(rows.end.previous_row()),
 6713            );
 6714            let text = buffer
 6715                .text_for_range(start..end)
 6716                .chain(Some("\n"))
 6717                .collect::<String>();
 6718            let insert_location = if upwards {
 6719                Point::new(rows.end.0, 0)
 6720            } else {
 6721                start
 6722            };
 6723            edits.push((insert_location..insert_location, text));
 6724        }
 6725
 6726        self.transact(cx, |this, cx| {
 6727            this.buffer.update(cx, |buffer, cx| {
 6728                buffer.edit(edits, None, cx);
 6729            });
 6730
 6731            this.request_autoscroll(Autoscroll::fit(), cx);
 6732        });
 6733    }
 6734
 6735    pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext<Self>) {
 6736        self.duplicate_line(true, cx);
 6737    }
 6738
 6739    pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext<Self>) {
 6740        self.duplicate_line(false, cx);
 6741    }
 6742
 6743    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
 6744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6745        let buffer = self.buffer.read(cx).snapshot(cx);
 6746
 6747        let mut edits = Vec::new();
 6748        let mut unfold_ranges = Vec::new();
 6749        let mut refold_ranges = Vec::new();
 6750
 6751        let selections = self.selections.all::<Point>(cx);
 6752        let mut selections = selections.iter().peekable();
 6753        let mut contiguous_row_selections = Vec::new();
 6754        let mut new_selections = Vec::new();
 6755
 6756        while let Some(selection) = selections.next() {
 6757            // Find all the selections that span a contiguous row range
 6758            let (start_row, end_row) = consume_contiguous_rows(
 6759                &mut contiguous_row_selections,
 6760                selection,
 6761                &display_map,
 6762                &mut selections,
 6763            );
 6764
 6765            // Move the text spanned by the row range to be before the line preceding the row range
 6766            if start_row.0 > 0 {
 6767                let range_to_move = Point::new(
 6768                    start_row.previous_row().0,
 6769                    buffer.line_len(start_row.previous_row()),
 6770                )
 6771                    ..Point::new(
 6772                        end_row.previous_row().0,
 6773                        buffer.line_len(end_row.previous_row()),
 6774                    );
 6775                let insertion_point = display_map
 6776                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 6777                    .0;
 6778
 6779                // Don't move lines across excerpts
 6780                if buffer
 6781                    .excerpt_boundaries_in_range((
 6782                        Bound::Excluded(insertion_point),
 6783                        Bound::Included(range_to_move.end),
 6784                    ))
 6785                    .next()
 6786                    .is_none()
 6787                {
 6788                    let text = buffer
 6789                        .text_for_range(range_to_move.clone())
 6790                        .flat_map(|s| s.chars())
 6791                        .skip(1)
 6792                        .chain(['\n'])
 6793                        .collect::<String>();
 6794
 6795                    edits.push((
 6796                        buffer.anchor_after(range_to_move.start)
 6797                            ..buffer.anchor_before(range_to_move.end),
 6798                        String::new(),
 6799                    ));
 6800                    let insertion_anchor = buffer.anchor_after(insertion_point);
 6801                    edits.push((insertion_anchor..insertion_anchor, text));
 6802
 6803                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 6804
 6805                    // Move selections up
 6806                    new_selections.extend(contiguous_row_selections.drain(..).map(
 6807                        |mut selection| {
 6808                            selection.start.row -= row_delta;
 6809                            selection.end.row -= row_delta;
 6810                            selection
 6811                        },
 6812                    ));
 6813
 6814                    // Move folds up
 6815                    unfold_ranges.push(range_to_move.clone());
 6816                    for fold in display_map.folds_in_range(
 6817                        buffer.anchor_before(range_to_move.start)
 6818                            ..buffer.anchor_after(range_to_move.end),
 6819                    ) {
 6820                        let mut start = fold.range.start.to_point(&buffer);
 6821                        let mut end = fold.range.end.to_point(&buffer);
 6822                        start.row -= row_delta;
 6823                        end.row -= row_delta;
 6824                        refold_ranges.push((start..end, fold.placeholder.clone()));
 6825                    }
 6826                }
 6827            }
 6828
 6829            // If we didn't move line(s), preserve the existing selections
 6830            new_selections.append(&mut contiguous_row_selections);
 6831        }
 6832
 6833        self.transact(cx, |this, cx| {
 6834            this.unfold_ranges(&unfold_ranges, true, true, cx);
 6835            this.buffer.update(cx, |buffer, cx| {
 6836                for (range, text) in edits {
 6837                    buffer.edit([(range, text)], None, cx);
 6838                }
 6839            });
 6840            this.fold_ranges(refold_ranges, true, cx);
 6841            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6842                s.select(new_selections);
 6843            })
 6844        });
 6845    }
 6846
 6847    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
 6848        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6849        let buffer = self.buffer.read(cx).snapshot(cx);
 6850
 6851        let mut edits = Vec::new();
 6852        let mut unfold_ranges = Vec::new();
 6853        let mut refold_ranges = Vec::new();
 6854
 6855        let selections = self.selections.all::<Point>(cx);
 6856        let mut selections = selections.iter().peekable();
 6857        let mut contiguous_row_selections = Vec::new();
 6858        let mut new_selections = Vec::new();
 6859
 6860        while let Some(selection) = selections.next() {
 6861            // Find all the selections that span a contiguous row range
 6862            let (start_row, end_row) = consume_contiguous_rows(
 6863                &mut contiguous_row_selections,
 6864                selection,
 6865                &display_map,
 6866                &mut selections,
 6867            );
 6868
 6869            // Move the text spanned by the row range to be after the last line of the row range
 6870            if end_row.0 <= buffer.max_point().row {
 6871                let range_to_move =
 6872                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 6873                let insertion_point = display_map
 6874                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 6875                    .0;
 6876
 6877                // Don't move lines across excerpt boundaries
 6878                if buffer
 6879                    .excerpt_boundaries_in_range((
 6880                        Bound::Excluded(range_to_move.start),
 6881                        Bound::Included(insertion_point),
 6882                    ))
 6883                    .next()
 6884                    .is_none()
 6885                {
 6886                    let mut text = String::from("\n");
 6887                    text.extend(buffer.text_for_range(range_to_move.clone()));
 6888                    text.pop(); // Drop trailing newline
 6889                    edits.push((
 6890                        buffer.anchor_after(range_to_move.start)
 6891                            ..buffer.anchor_before(range_to_move.end),
 6892                        String::new(),
 6893                    ));
 6894                    let insertion_anchor = buffer.anchor_after(insertion_point);
 6895                    edits.push((insertion_anchor..insertion_anchor, text));
 6896
 6897                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 6898
 6899                    // Move selections down
 6900                    new_selections.extend(contiguous_row_selections.drain(..).map(
 6901                        |mut selection| {
 6902                            selection.start.row += row_delta;
 6903                            selection.end.row += row_delta;
 6904                            selection
 6905                        },
 6906                    ));
 6907
 6908                    // Move folds down
 6909                    unfold_ranges.push(range_to_move.clone());
 6910                    for fold in display_map.folds_in_range(
 6911                        buffer.anchor_before(range_to_move.start)
 6912                            ..buffer.anchor_after(range_to_move.end),
 6913                    ) {
 6914                        let mut start = fold.range.start.to_point(&buffer);
 6915                        let mut end = fold.range.end.to_point(&buffer);
 6916                        start.row += row_delta;
 6917                        end.row += row_delta;
 6918                        refold_ranges.push((start..end, fold.placeholder.clone()));
 6919                    }
 6920                }
 6921            }
 6922
 6923            // If we didn't move line(s), preserve the existing selections
 6924            new_selections.append(&mut contiguous_row_selections);
 6925        }
 6926
 6927        self.transact(cx, |this, cx| {
 6928            this.unfold_ranges(&unfold_ranges, true, true, cx);
 6929            this.buffer.update(cx, |buffer, cx| {
 6930                for (range, text) in edits {
 6931                    buffer.edit([(range, text)], None, cx);
 6932                }
 6933            });
 6934            this.fold_ranges(refold_ranges, true, cx);
 6935            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 6936        });
 6937    }
 6938
 6939    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
 6940        let text_layout_details = &self.text_layout_details(cx);
 6941        self.transact(cx, |this, cx| {
 6942            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6943                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 6944                let line_mode = s.line_mode;
 6945                s.move_with(|display_map, selection| {
 6946                    if !selection.is_empty() || line_mode {
 6947                        return;
 6948                    }
 6949
 6950                    let mut head = selection.head();
 6951                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 6952                    if head.column() == display_map.line_len(head.row()) {
 6953                        transpose_offset = display_map
 6954                            .buffer_snapshot
 6955                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6956                    }
 6957
 6958                    if transpose_offset == 0 {
 6959                        return;
 6960                    }
 6961
 6962                    *head.column_mut() += 1;
 6963                    head = display_map.clip_point(head, Bias::Right);
 6964                    let goal = SelectionGoal::HorizontalPosition(
 6965                        display_map
 6966                            .x_for_display_point(head, text_layout_details)
 6967                            .into(),
 6968                    );
 6969                    selection.collapse_to(head, goal);
 6970
 6971                    let transpose_start = display_map
 6972                        .buffer_snapshot
 6973                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6974                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 6975                        let transpose_end = display_map
 6976                            .buffer_snapshot
 6977                            .clip_offset(transpose_offset + 1, Bias::Right);
 6978                        if let Some(ch) =
 6979                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 6980                        {
 6981                            edits.push((transpose_start..transpose_offset, String::new()));
 6982                            edits.push((transpose_end..transpose_end, ch.to_string()));
 6983                        }
 6984                    }
 6985                });
 6986                edits
 6987            });
 6988            this.buffer
 6989                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 6990            let selections = this.selections.all::<usize>(cx);
 6991            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6992                s.select(selections);
 6993            });
 6994        });
 6995    }
 6996
 6997    pub fn rewrap(&mut self, _: &Rewrap, cx: &mut ViewContext<Self>) {
 6998        self.rewrap_impl(true, cx)
 6999    }
 7000
 7001    pub fn rewrap_impl(&mut self, only_text: bool, cx: &mut ViewContext<Self>) {
 7002        let buffer = self.buffer.read(cx).snapshot(cx);
 7003        let selections = self.selections.all::<Point>(cx);
 7004        let mut selections = selections.iter().peekable();
 7005
 7006        let mut edits = Vec::new();
 7007        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
 7008
 7009        while let Some(selection) = selections.next() {
 7010            let mut start_row = selection.start.row;
 7011            let mut end_row = selection.end.row;
 7012
 7013            // Skip selections that overlap with a range that has already been rewrapped.
 7014            let selection_range = start_row..end_row;
 7015            if rewrapped_row_ranges
 7016                .iter()
 7017                .any(|range| range.overlaps(&selection_range))
 7018            {
 7019                continue;
 7020            }
 7021
 7022            let mut should_rewrap = !only_text;
 7023
 7024            if let Some(language_scope) = buffer.language_scope_at(selection.head()) {
 7025                match language_scope.language_name().0.as_ref() {
 7026                    "Markdown" | "Plain Text" => {
 7027                        should_rewrap = true;
 7028                    }
 7029                    _ => {}
 7030                }
 7031            }
 7032
 7033            let tab_size = buffer.settings_at(selection.head(), cx).tab_size;
 7034
 7035            // Since not all lines in the selection may be at the same indent
 7036            // level, choose the indent size that is the most common between all
 7037            // of the lines.
 7038            //
 7039            // If there is a tie, we use the deepest indent.
 7040            let (indent_size, indent_end) = {
 7041                let mut indent_size_occurrences = HashMap::default();
 7042                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
 7043
 7044                for row in start_row..=end_row {
 7045                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
 7046                    rows_by_indent_size.entry(indent).or_default().push(row);
 7047                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
 7048                }
 7049
 7050                let indent_size = indent_size_occurrences
 7051                    .into_iter()
 7052                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
 7053                    .map(|(indent, _)| indent)
 7054                    .unwrap_or_default();
 7055                let row = rows_by_indent_size[&indent_size][0];
 7056                let indent_end = Point::new(row, indent_size.len);
 7057
 7058                (indent_size, indent_end)
 7059            };
 7060
 7061            let mut line_prefix = indent_size.chars().collect::<String>();
 7062
 7063            if let Some(comment_prefix) =
 7064                buffer
 7065                    .language_scope_at(selection.head())
 7066                    .and_then(|language| {
 7067                        language
 7068                            .line_comment_prefixes()
 7069                            .iter()
 7070                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
 7071                            .cloned()
 7072                    })
 7073            {
 7074                line_prefix.push_str(&comment_prefix);
 7075                should_rewrap = true;
 7076            }
 7077
 7078            if !should_rewrap {
 7079                continue;
 7080            }
 7081
 7082            if selection.is_empty() {
 7083                'expand_upwards: while start_row > 0 {
 7084                    let prev_row = start_row - 1;
 7085                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
 7086                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
 7087                    {
 7088                        start_row = prev_row;
 7089                    } else {
 7090                        break 'expand_upwards;
 7091                    }
 7092                }
 7093
 7094                'expand_downwards: while end_row < buffer.max_point().row {
 7095                    let next_row = end_row + 1;
 7096                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
 7097                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
 7098                    {
 7099                        end_row = next_row;
 7100                    } else {
 7101                        break 'expand_downwards;
 7102                    }
 7103                }
 7104            }
 7105
 7106            let start = Point::new(start_row, 0);
 7107            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
 7108            let selection_text = buffer.text_for_range(start..end).collect::<String>();
 7109            let Some(lines_without_prefixes) = selection_text
 7110                .lines()
 7111                .map(|line| {
 7112                    line.strip_prefix(&line_prefix)
 7113                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
 7114                        .ok_or_else(|| {
 7115                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
 7116                        })
 7117                })
 7118                .collect::<Result<Vec<_>, _>>()
 7119                .log_err()
 7120            else {
 7121                continue;
 7122            };
 7123
 7124            let wrap_column = buffer
 7125                .settings_at(Point::new(start_row, 0), cx)
 7126                .preferred_line_length as usize;
 7127            let wrapped_text = wrap_with_prefix(
 7128                line_prefix,
 7129                lines_without_prefixes.join(" "),
 7130                wrap_column,
 7131                tab_size,
 7132            );
 7133
 7134            let diff = TextDiff::from_lines(&selection_text, &wrapped_text);
 7135            let mut offset = start.to_offset(&buffer);
 7136            let mut moved_since_edit = true;
 7137
 7138            for change in diff.iter_all_changes() {
 7139                let value = change.value();
 7140                match change.tag() {
 7141                    ChangeTag::Equal => {
 7142                        offset += value.len();
 7143                        moved_since_edit = true;
 7144                    }
 7145                    ChangeTag::Delete => {
 7146                        let start = buffer.anchor_after(offset);
 7147                        let end = buffer.anchor_before(offset + value.len());
 7148
 7149                        if moved_since_edit {
 7150                            edits.push((start..end, String::new()));
 7151                        } else {
 7152                            edits.last_mut().unwrap().0.end = end;
 7153                        }
 7154
 7155                        offset += value.len();
 7156                        moved_since_edit = false;
 7157                    }
 7158                    ChangeTag::Insert => {
 7159                        if moved_since_edit {
 7160                            let anchor = buffer.anchor_after(offset);
 7161                            edits.push((anchor..anchor, value.to_string()));
 7162                        } else {
 7163                            edits.last_mut().unwrap().1.push_str(value);
 7164                        }
 7165
 7166                        moved_since_edit = false;
 7167                    }
 7168                }
 7169            }
 7170
 7171            rewrapped_row_ranges.push(start_row..=end_row);
 7172        }
 7173
 7174        self.buffer
 7175            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 7176    }
 7177
 7178    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
 7179        let mut text = String::new();
 7180        let buffer = self.buffer.read(cx).snapshot(cx);
 7181        let mut selections = self.selections.all::<Point>(cx);
 7182        let mut clipboard_selections = Vec::with_capacity(selections.len());
 7183        {
 7184            let max_point = buffer.max_point();
 7185            let mut is_first = true;
 7186            for selection in &mut selections {
 7187                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 7188                if is_entire_line {
 7189                    selection.start = Point::new(selection.start.row, 0);
 7190                    if !selection.is_empty() && selection.end.column == 0 {
 7191                        selection.end = cmp::min(max_point, selection.end);
 7192                    } else {
 7193                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 7194                    }
 7195                    selection.goal = SelectionGoal::None;
 7196                }
 7197                if is_first {
 7198                    is_first = false;
 7199                } else {
 7200                    text += "\n";
 7201                }
 7202                let mut len = 0;
 7203                for chunk in buffer.text_for_range(selection.start..selection.end) {
 7204                    text.push_str(chunk);
 7205                    len += chunk.len();
 7206                }
 7207                clipboard_selections.push(ClipboardSelection {
 7208                    len,
 7209                    is_entire_line,
 7210                    first_line_indent: buffer
 7211                        .indent_size_for_line(MultiBufferRow(selection.start.row))
 7212                        .len,
 7213                });
 7214            }
 7215        }
 7216
 7217        self.transact(cx, |this, cx| {
 7218            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7219                s.select(selections);
 7220            });
 7221            this.insert("", cx);
 7222            cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
 7223                text,
 7224                clipboard_selections,
 7225            ));
 7226        });
 7227    }
 7228
 7229    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
 7230        let selections = self.selections.all::<Point>(cx);
 7231        let buffer = self.buffer.read(cx).read(cx);
 7232        let mut text = String::new();
 7233
 7234        let mut clipboard_selections = Vec::with_capacity(selections.len());
 7235        {
 7236            let max_point = buffer.max_point();
 7237            let mut is_first = true;
 7238            for selection in selections.iter() {
 7239                let mut start = selection.start;
 7240                let mut end = selection.end;
 7241                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 7242                if is_entire_line {
 7243                    start = Point::new(start.row, 0);
 7244                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 7245                }
 7246                if is_first {
 7247                    is_first = false;
 7248                } else {
 7249                    text += "\n";
 7250                }
 7251                let mut len = 0;
 7252                for chunk in buffer.text_for_range(start..end) {
 7253                    text.push_str(chunk);
 7254                    len += chunk.len();
 7255                }
 7256                clipboard_selections.push(ClipboardSelection {
 7257                    len,
 7258                    is_entire_line,
 7259                    first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
 7260                });
 7261            }
 7262        }
 7263
 7264        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
 7265            text,
 7266            clipboard_selections,
 7267        ));
 7268    }
 7269
 7270    pub fn do_paste(
 7271        &mut self,
 7272        text: &String,
 7273        clipboard_selections: Option<Vec<ClipboardSelection>>,
 7274        handle_entire_lines: bool,
 7275        cx: &mut ViewContext<Self>,
 7276    ) {
 7277        if self.read_only(cx) {
 7278            return;
 7279        }
 7280
 7281        let clipboard_text = Cow::Borrowed(text);
 7282
 7283        self.transact(cx, |this, cx| {
 7284            if let Some(mut clipboard_selections) = clipboard_selections {
 7285                let old_selections = this.selections.all::<usize>(cx);
 7286                let all_selections_were_entire_line =
 7287                    clipboard_selections.iter().all(|s| s.is_entire_line);
 7288                let first_selection_indent_column =
 7289                    clipboard_selections.first().map(|s| s.first_line_indent);
 7290                if clipboard_selections.len() != old_selections.len() {
 7291                    clipboard_selections.drain(..);
 7292                }
 7293                let cursor_offset = this.selections.last::<usize>(cx).head();
 7294                let mut auto_indent_on_paste = true;
 7295
 7296                this.buffer.update(cx, |buffer, cx| {
 7297                    let snapshot = buffer.read(cx);
 7298                    auto_indent_on_paste =
 7299                        snapshot.settings_at(cursor_offset, cx).auto_indent_on_paste;
 7300
 7301                    let mut start_offset = 0;
 7302                    let mut edits = Vec::new();
 7303                    let mut original_indent_columns = Vec::new();
 7304                    for (ix, selection) in old_selections.iter().enumerate() {
 7305                        let to_insert;
 7306                        let entire_line;
 7307                        let original_indent_column;
 7308                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 7309                            let end_offset = start_offset + clipboard_selection.len;
 7310                            to_insert = &clipboard_text[start_offset..end_offset];
 7311                            entire_line = clipboard_selection.is_entire_line;
 7312                            start_offset = end_offset + 1;
 7313                            original_indent_column = Some(clipboard_selection.first_line_indent);
 7314                        } else {
 7315                            to_insert = clipboard_text.as_str();
 7316                            entire_line = all_selections_were_entire_line;
 7317                            original_indent_column = first_selection_indent_column
 7318                        }
 7319
 7320                        // If the corresponding selection was empty when this slice of the
 7321                        // clipboard text was written, then the entire line containing the
 7322                        // selection was copied. If this selection is also currently empty,
 7323                        // then paste the line before the current line of the buffer.
 7324                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
 7325                            let column = selection.start.to_point(&snapshot).column as usize;
 7326                            let line_start = selection.start - column;
 7327                            line_start..line_start
 7328                        } else {
 7329                            selection.range()
 7330                        };
 7331
 7332                        edits.push((range, to_insert));
 7333                        original_indent_columns.extend(original_indent_column);
 7334                    }
 7335                    drop(snapshot);
 7336
 7337                    buffer.edit(
 7338                        edits,
 7339                        if auto_indent_on_paste {
 7340                            Some(AutoindentMode::Block {
 7341                                original_indent_columns,
 7342                            })
 7343                        } else {
 7344                            None
 7345                        },
 7346                        cx,
 7347                    );
 7348                });
 7349
 7350                let selections = this.selections.all::<usize>(cx);
 7351                this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 7352            } else {
 7353                this.insert(&clipboard_text, cx);
 7354            }
 7355        });
 7356    }
 7357
 7358    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
 7359        if let Some(item) = cx.read_from_clipboard() {
 7360            let entries = item.entries();
 7361
 7362            match entries.first() {
 7363                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
 7364                // of all the pasted entries.
 7365                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
 7366                    .do_paste(
 7367                        clipboard_string.text(),
 7368                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
 7369                        true,
 7370                        cx,
 7371                    ),
 7372                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, cx),
 7373            }
 7374        }
 7375    }
 7376
 7377    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
 7378        if self.read_only(cx) {
 7379            return;
 7380        }
 7381
 7382        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 7383            if let Some((selections, _)) =
 7384                self.selection_history.transaction(transaction_id).cloned()
 7385            {
 7386                self.change_selections(None, cx, |s| {
 7387                    s.select_anchors(selections.to_vec());
 7388                });
 7389            }
 7390            self.request_autoscroll(Autoscroll::fit(), cx);
 7391            self.unmark_text(cx);
 7392            self.refresh_inline_completion(true, false, cx);
 7393            cx.emit(EditorEvent::Edited { transaction_id });
 7394            cx.emit(EditorEvent::TransactionUndone { transaction_id });
 7395        }
 7396    }
 7397
 7398    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 7399        if self.read_only(cx) {
 7400            return;
 7401        }
 7402
 7403        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 7404            if let Some((_, Some(selections))) =
 7405                self.selection_history.transaction(transaction_id).cloned()
 7406            {
 7407                self.change_selections(None, cx, |s| {
 7408                    s.select_anchors(selections.to_vec());
 7409                });
 7410            }
 7411            self.request_autoscroll(Autoscroll::fit(), cx);
 7412            self.unmark_text(cx);
 7413            self.refresh_inline_completion(true, false, cx);
 7414            cx.emit(EditorEvent::Edited { transaction_id });
 7415        }
 7416    }
 7417
 7418    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 7419        self.buffer
 7420            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 7421    }
 7422
 7423    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut ViewContext<Self>) {
 7424        self.buffer
 7425            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
 7426    }
 7427
 7428    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 7429        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7430            let line_mode = s.line_mode;
 7431            s.move_with(|map, selection| {
 7432                let cursor = if selection.is_empty() && !line_mode {
 7433                    movement::left(map, selection.start)
 7434                } else {
 7435                    selection.start
 7436                };
 7437                selection.collapse_to(cursor, SelectionGoal::None);
 7438            });
 7439        })
 7440    }
 7441
 7442    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 7443        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7444            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 7445        })
 7446    }
 7447
 7448    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 7449        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7450            let line_mode = s.line_mode;
 7451            s.move_with(|map, selection| {
 7452                let cursor = if selection.is_empty() && !line_mode {
 7453                    movement::right(map, selection.end)
 7454                } else {
 7455                    selection.end
 7456                };
 7457                selection.collapse_to(cursor, SelectionGoal::None)
 7458            });
 7459        })
 7460    }
 7461
 7462    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 7463        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7464            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 7465        })
 7466    }
 7467
 7468    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 7469        if self.take_rename(true, cx).is_some() {
 7470            return;
 7471        }
 7472
 7473        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7474            cx.propagate();
 7475            return;
 7476        }
 7477
 7478        let text_layout_details = &self.text_layout_details(cx);
 7479        let selection_count = self.selections.count();
 7480        let first_selection = self.selections.first_anchor();
 7481
 7482        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7483            let line_mode = s.line_mode;
 7484            s.move_with(|map, selection| {
 7485                if !selection.is_empty() && !line_mode {
 7486                    selection.goal = SelectionGoal::None;
 7487                }
 7488                let (cursor, goal) = movement::up(
 7489                    map,
 7490                    selection.start,
 7491                    selection.goal,
 7492                    false,
 7493                    text_layout_details,
 7494                );
 7495                selection.collapse_to(cursor, goal);
 7496            });
 7497        });
 7498
 7499        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 7500        {
 7501            cx.propagate();
 7502        }
 7503    }
 7504
 7505    pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
 7506        if self.take_rename(true, cx).is_some() {
 7507            return;
 7508        }
 7509
 7510        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7511            cx.propagate();
 7512            return;
 7513        }
 7514
 7515        let text_layout_details = &self.text_layout_details(cx);
 7516
 7517        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7518            let line_mode = s.line_mode;
 7519            s.move_with(|map, selection| {
 7520                if !selection.is_empty() && !line_mode {
 7521                    selection.goal = SelectionGoal::None;
 7522                }
 7523                let (cursor, goal) = movement::up_by_rows(
 7524                    map,
 7525                    selection.start,
 7526                    action.lines,
 7527                    selection.goal,
 7528                    false,
 7529                    text_layout_details,
 7530                );
 7531                selection.collapse_to(cursor, goal);
 7532            });
 7533        })
 7534    }
 7535
 7536    pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext<Self>) {
 7537        if self.take_rename(true, cx).is_some() {
 7538            return;
 7539        }
 7540
 7541        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7542            cx.propagate();
 7543            return;
 7544        }
 7545
 7546        let text_layout_details = &self.text_layout_details(cx);
 7547
 7548        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7549            let line_mode = s.line_mode;
 7550            s.move_with(|map, selection| {
 7551                if !selection.is_empty() && !line_mode {
 7552                    selection.goal = SelectionGoal::None;
 7553                }
 7554                let (cursor, goal) = movement::down_by_rows(
 7555                    map,
 7556                    selection.start,
 7557                    action.lines,
 7558                    selection.goal,
 7559                    false,
 7560                    text_layout_details,
 7561                );
 7562                selection.collapse_to(cursor, goal);
 7563            });
 7564        })
 7565    }
 7566
 7567    pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext<Self>) {
 7568        let text_layout_details = &self.text_layout_details(cx);
 7569        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7570            s.move_heads_with(|map, head, goal| {
 7571                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
 7572            })
 7573        })
 7574    }
 7575
 7576    pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext<Self>) {
 7577        let text_layout_details = &self.text_layout_details(cx);
 7578        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7579            s.move_heads_with(|map, head, goal| {
 7580                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
 7581            })
 7582        })
 7583    }
 7584
 7585    pub fn select_page_up(&mut self, _: &SelectPageUp, cx: &mut ViewContext<Self>) {
 7586        let Some(row_count) = self.visible_row_count() else {
 7587            return;
 7588        };
 7589
 7590        let text_layout_details = &self.text_layout_details(cx);
 7591
 7592        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7593            s.move_heads_with(|map, head, goal| {
 7594                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
 7595            })
 7596        })
 7597    }
 7598
 7599    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
 7600        if self.take_rename(true, cx).is_some() {
 7601            return;
 7602        }
 7603
 7604        if self
 7605            .context_menu
 7606            .write()
 7607            .as_mut()
 7608            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
 7609            .unwrap_or(false)
 7610        {
 7611            return;
 7612        }
 7613
 7614        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7615            cx.propagate();
 7616            return;
 7617        }
 7618
 7619        let Some(row_count) = self.visible_row_count() else {
 7620            return;
 7621        };
 7622
 7623        let autoscroll = if action.center_cursor {
 7624            Autoscroll::center()
 7625        } else {
 7626            Autoscroll::fit()
 7627        };
 7628
 7629        let text_layout_details = &self.text_layout_details(cx);
 7630
 7631        self.change_selections(Some(autoscroll), cx, |s| {
 7632            let line_mode = s.line_mode;
 7633            s.move_with(|map, selection| {
 7634                if !selection.is_empty() && !line_mode {
 7635                    selection.goal = SelectionGoal::None;
 7636                }
 7637                let (cursor, goal) = movement::up_by_rows(
 7638                    map,
 7639                    selection.end,
 7640                    row_count,
 7641                    selection.goal,
 7642                    false,
 7643                    text_layout_details,
 7644                );
 7645                selection.collapse_to(cursor, goal);
 7646            });
 7647        });
 7648    }
 7649
 7650    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 7651        let text_layout_details = &self.text_layout_details(cx);
 7652        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7653            s.move_heads_with(|map, head, goal| {
 7654                movement::up(map, head, goal, false, text_layout_details)
 7655            })
 7656        })
 7657    }
 7658
 7659    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 7660        self.take_rename(true, cx);
 7661
 7662        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7663            cx.propagate();
 7664            return;
 7665        }
 7666
 7667        let text_layout_details = &self.text_layout_details(cx);
 7668        let selection_count = self.selections.count();
 7669        let first_selection = self.selections.first_anchor();
 7670
 7671        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7672            let line_mode = s.line_mode;
 7673            s.move_with(|map, selection| {
 7674                if !selection.is_empty() && !line_mode {
 7675                    selection.goal = SelectionGoal::None;
 7676                }
 7677                let (cursor, goal) = movement::down(
 7678                    map,
 7679                    selection.end,
 7680                    selection.goal,
 7681                    false,
 7682                    text_layout_details,
 7683                );
 7684                selection.collapse_to(cursor, goal);
 7685            });
 7686        });
 7687
 7688        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 7689        {
 7690            cx.propagate();
 7691        }
 7692    }
 7693
 7694    pub fn select_page_down(&mut self, _: &SelectPageDown, cx: &mut ViewContext<Self>) {
 7695        let Some(row_count) = self.visible_row_count() else {
 7696            return;
 7697        };
 7698
 7699        let text_layout_details = &self.text_layout_details(cx);
 7700
 7701        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7702            s.move_heads_with(|map, head, goal| {
 7703                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
 7704            })
 7705        })
 7706    }
 7707
 7708    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
 7709        if self.take_rename(true, cx).is_some() {
 7710            return;
 7711        }
 7712
 7713        if self
 7714            .context_menu
 7715            .write()
 7716            .as_mut()
 7717            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
 7718            .unwrap_or(false)
 7719        {
 7720            return;
 7721        }
 7722
 7723        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7724            cx.propagate();
 7725            return;
 7726        }
 7727
 7728        let Some(row_count) = self.visible_row_count() else {
 7729            return;
 7730        };
 7731
 7732        let autoscroll = if action.center_cursor {
 7733            Autoscroll::center()
 7734        } else {
 7735            Autoscroll::fit()
 7736        };
 7737
 7738        let text_layout_details = &self.text_layout_details(cx);
 7739        self.change_selections(Some(autoscroll), cx, |s| {
 7740            let line_mode = s.line_mode;
 7741            s.move_with(|map, selection| {
 7742                if !selection.is_empty() && !line_mode {
 7743                    selection.goal = SelectionGoal::None;
 7744                }
 7745                let (cursor, goal) = movement::down_by_rows(
 7746                    map,
 7747                    selection.end,
 7748                    row_count,
 7749                    selection.goal,
 7750                    false,
 7751                    text_layout_details,
 7752                );
 7753                selection.collapse_to(cursor, goal);
 7754            });
 7755        });
 7756    }
 7757
 7758    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 7759        let text_layout_details = &self.text_layout_details(cx);
 7760        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7761            s.move_heads_with(|map, head, goal| {
 7762                movement::down(map, head, goal, false, text_layout_details)
 7763            })
 7764        });
 7765    }
 7766
 7767    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
 7768        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7769            context_menu.select_first(self.completion_provider.as_deref(), cx);
 7770        }
 7771    }
 7772
 7773    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
 7774        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7775            context_menu.select_prev(self.completion_provider.as_deref(), cx);
 7776        }
 7777    }
 7778
 7779    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
 7780        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7781            context_menu.select_next(self.completion_provider.as_deref(), cx);
 7782        }
 7783    }
 7784
 7785    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
 7786        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7787            context_menu.select_last(self.completion_provider.as_deref(), cx);
 7788        }
 7789    }
 7790
 7791    pub fn move_to_previous_word_start(
 7792        &mut self,
 7793        _: &MoveToPreviousWordStart,
 7794        cx: &mut ViewContext<Self>,
 7795    ) {
 7796        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7797            s.move_cursors_with(|map, head, _| {
 7798                (
 7799                    movement::previous_word_start(map, head),
 7800                    SelectionGoal::None,
 7801                )
 7802            });
 7803        })
 7804    }
 7805
 7806    pub fn move_to_previous_subword_start(
 7807        &mut self,
 7808        _: &MoveToPreviousSubwordStart,
 7809        cx: &mut ViewContext<Self>,
 7810    ) {
 7811        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7812            s.move_cursors_with(|map, head, _| {
 7813                (
 7814                    movement::previous_subword_start(map, head),
 7815                    SelectionGoal::None,
 7816                )
 7817            });
 7818        })
 7819    }
 7820
 7821    pub fn select_to_previous_word_start(
 7822        &mut self,
 7823        _: &SelectToPreviousWordStart,
 7824        cx: &mut ViewContext<Self>,
 7825    ) {
 7826        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7827            s.move_heads_with(|map, head, _| {
 7828                (
 7829                    movement::previous_word_start(map, head),
 7830                    SelectionGoal::None,
 7831                )
 7832            });
 7833        })
 7834    }
 7835
 7836    pub fn select_to_previous_subword_start(
 7837        &mut self,
 7838        _: &SelectToPreviousSubwordStart,
 7839        cx: &mut ViewContext<Self>,
 7840    ) {
 7841        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7842            s.move_heads_with(|map, head, _| {
 7843                (
 7844                    movement::previous_subword_start(map, head),
 7845                    SelectionGoal::None,
 7846                )
 7847            });
 7848        })
 7849    }
 7850
 7851    pub fn delete_to_previous_word_start(
 7852        &mut self,
 7853        action: &DeleteToPreviousWordStart,
 7854        cx: &mut ViewContext<Self>,
 7855    ) {
 7856        self.transact(cx, |this, cx| {
 7857            this.select_autoclose_pair(cx);
 7858            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7859                let line_mode = s.line_mode;
 7860                s.move_with(|map, selection| {
 7861                    if selection.is_empty() && !line_mode {
 7862                        let cursor = if action.ignore_newlines {
 7863                            movement::previous_word_start(map, selection.head())
 7864                        } else {
 7865                            movement::previous_word_start_or_newline(map, selection.head())
 7866                        };
 7867                        selection.set_head(cursor, SelectionGoal::None);
 7868                    }
 7869                });
 7870            });
 7871            this.insert("", cx);
 7872        });
 7873    }
 7874
 7875    pub fn delete_to_previous_subword_start(
 7876        &mut self,
 7877        _: &DeleteToPreviousSubwordStart,
 7878        cx: &mut ViewContext<Self>,
 7879    ) {
 7880        self.transact(cx, |this, cx| {
 7881            this.select_autoclose_pair(cx);
 7882            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7883                let line_mode = s.line_mode;
 7884                s.move_with(|map, selection| {
 7885                    if selection.is_empty() && !line_mode {
 7886                        let cursor = movement::previous_subword_start(map, selection.head());
 7887                        selection.set_head(cursor, SelectionGoal::None);
 7888                    }
 7889                });
 7890            });
 7891            this.insert("", cx);
 7892        });
 7893    }
 7894
 7895    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 7896        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7897            s.move_cursors_with(|map, head, _| {
 7898                (movement::next_word_end(map, head), SelectionGoal::None)
 7899            });
 7900        })
 7901    }
 7902
 7903    pub fn move_to_next_subword_end(
 7904        &mut self,
 7905        _: &MoveToNextSubwordEnd,
 7906        cx: &mut ViewContext<Self>,
 7907    ) {
 7908        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7909            s.move_cursors_with(|map, head, _| {
 7910                (movement::next_subword_end(map, head), SelectionGoal::None)
 7911            });
 7912        })
 7913    }
 7914
 7915    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 7916        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7917            s.move_heads_with(|map, head, _| {
 7918                (movement::next_word_end(map, head), SelectionGoal::None)
 7919            });
 7920        })
 7921    }
 7922
 7923    pub fn select_to_next_subword_end(
 7924        &mut self,
 7925        _: &SelectToNextSubwordEnd,
 7926        cx: &mut ViewContext<Self>,
 7927    ) {
 7928        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7929            s.move_heads_with(|map, head, _| {
 7930                (movement::next_subword_end(map, head), SelectionGoal::None)
 7931            });
 7932        })
 7933    }
 7934
 7935    pub fn delete_to_next_word_end(
 7936        &mut self,
 7937        action: &DeleteToNextWordEnd,
 7938        cx: &mut ViewContext<Self>,
 7939    ) {
 7940        self.transact(cx, |this, cx| {
 7941            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7942                let line_mode = s.line_mode;
 7943                s.move_with(|map, selection| {
 7944                    if selection.is_empty() && !line_mode {
 7945                        let cursor = if action.ignore_newlines {
 7946                            movement::next_word_end(map, selection.head())
 7947                        } else {
 7948                            movement::next_word_end_or_newline(map, selection.head())
 7949                        };
 7950                        selection.set_head(cursor, SelectionGoal::None);
 7951                    }
 7952                });
 7953            });
 7954            this.insert("", cx);
 7955        });
 7956    }
 7957
 7958    pub fn delete_to_next_subword_end(
 7959        &mut self,
 7960        _: &DeleteToNextSubwordEnd,
 7961        cx: &mut ViewContext<Self>,
 7962    ) {
 7963        self.transact(cx, |this, cx| {
 7964            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7965                s.move_with(|map, selection| {
 7966                    if selection.is_empty() {
 7967                        let cursor = movement::next_subword_end(map, selection.head());
 7968                        selection.set_head(cursor, SelectionGoal::None);
 7969                    }
 7970                });
 7971            });
 7972            this.insert("", cx);
 7973        });
 7974    }
 7975
 7976    pub fn move_to_beginning_of_line(
 7977        &mut self,
 7978        action: &MoveToBeginningOfLine,
 7979        cx: &mut ViewContext<Self>,
 7980    ) {
 7981        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7982            s.move_cursors_with(|map, head, _| {
 7983                (
 7984                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 7985                    SelectionGoal::None,
 7986                )
 7987            });
 7988        })
 7989    }
 7990
 7991    pub fn select_to_beginning_of_line(
 7992        &mut self,
 7993        action: &SelectToBeginningOfLine,
 7994        cx: &mut ViewContext<Self>,
 7995    ) {
 7996        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7997            s.move_heads_with(|map, head, _| {
 7998                (
 7999                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 8000                    SelectionGoal::None,
 8001                )
 8002            });
 8003        });
 8004    }
 8005
 8006    pub fn delete_to_beginning_of_line(
 8007        &mut self,
 8008        _: &DeleteToBeginningOfLine,
 8009        cx: &mut ViewContext<Self>,
 8010    ) {
 8011        self.transact(cx, |this, cx| {
 8012            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8013                s.move_with(|_, selection| {
 8014                    selection.reversed = true;
 8015                });
 8016            });
 8017
 8018            this.select_to_beginning_of_line(
 8019                &SelectToBeginningOfLine {
 8020                    stop_at_soft_wraps: false,
 8021                },
 8022                cx,
 8023            );
 8024            this.backspace(&Backspace, cx);
 8025        });
 8026    }
 8027
 8028    pub fn move_to_end_of_line(&mut self, action: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 8029        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8030            s.move_cursors_with(|map, head, _| {
 8031                (
 8032                    movement::line_end(map, head, action.stop_at_soft_wraps),
 8033                    SelectionGoal::None,
 8034                )
 8035            });
 8036        })
 8037    }
 8038
 8039    pub fn select_to_end_of_line(
 8040        &mut self,
 8041        action: &SelectToEndOfLine,
 8042        cx: &mut ViewContext<Self>,
 8043    ) {
 8044        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8045            s.move_heads_with(|map, head, _| {
 8046                (
 8047                    movement::line_end(map, head, action.stop_at_soft_wraps),
 8048                    SelectionGoal::None,
 8049                )
 8050            });
 8051        })
 8052    }
 8053
 8054    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 8055        self.transact(cx, |this, cx| {
 8056            this.select_to_end_of_line(
 8057                &SelectToEndOfLine {
 8058                    stop_at_soft_wraps: false,
 8059                },
 8060                cx,
 8061            );
 8062            this.delete(&Delete, cx);
 8063        });
 8064    }
 8065
 8066    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 8067        self.transact(cx, |this, cx| {
 8068            this.select_to_end_of_line(
 8069                &SelectToEndOfLine {
 8070                    stop_at_soft_wraps: false,
 8071                },
 8072                cx,
 8073            );
 8074            this.cut(&Cut, cx);
 8075        });
 8076    }
 8077
 8078    pub fn move_to_start_of_paragraph(
 8079        &mut self,
 8080        _: &MoveToStartOfParagraph,
 8081        cx: &mut ViewContext<Self>,
 8082    ) {
 8083        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8084            cx.propagate();
 8085            return;
 8086        }
 8087
 8088        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8089            s.move_with(|map, selection| {
 8090                selection.collapse_to(
 8091                    movement::start_of_paragraph(map, selection.head(), 1),
 8092                    SelectionGoal::None,
 8093                )
 8094            });
 8095        })
 8096    }
 8097
 8098    pub fn move_to_end_of_paragraph(
 8099        &mut self,
 8100        _: &MoveToEndOfParagraph,
 8101        cx: &mut ViewContext<Self>,
 8102    ) {
 8103        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8104            cx.propagate();
 8105            return;
 8106        }
 8107
 8108        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8109            s.move_with(|map, selection| {
 8110                selection.collapse_to(
 8111                    movement::end_of_paragraph(map, selection.head(), 1),
 8112                    SelectionGoal::None,
 8113                )
 8114            });
 8115        })
 8116    }
 8117
 8118    pub fn select_to_start_of_paragraph(
 8119        &mut self,
 8120        _: &SelectToStartOfParagraph,
 8121        cx: &mut ViewContext<Self>,
 8122    ) {
 8123        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8124            cx.propagate();
 8125            return;
 8126        }
 8127
 8128        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8129            s.move_heads_with(|map, head, _| {
 8130                (
 8131                    movement::start_of_paragraph(map, head, 1),
 8132                    SelectionGoal::None,
 8133                )
 8134            });
 8135        })
 8136    }
 8137
 8138    pub fn select_to_end_of_paragraph(
 8139        &mut self,
 8140        _: &SelectToEndOfParagraph,
 8141        cx: &mut ViewContext<Self>,
 8142    ) {
 8143        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8144            cx.propagate();
 8145            return;
 8146        }
 8147
 8148        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8149            s.move_heads_with(|map, head, _| {
 8150                (
 8151                    movement::end_of_paragraph(map, head, 1),
 8152                    SelectionGoal::None,
 8153                )
 8154            });
 8155        })
 8156    }
 8157
 8158    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 8159        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8160            cx.propagate();
 8161            return;
 8162        }
 8163
 8164        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8165            s.select_ranges(vec![0..0]);
 8166        });
 8167    }
 8168
 8169    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 8170        let mut selection = self.selections.last::<Point>(cx);
 8171        selection.set_head(Point::zero(), SelectionGoal::None);
 8172
 8173        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8174            s.select(vec![selection]);
 8175        });
 8176    }
 8177
 8178    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 8179        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8180            cx.propagate();
 8181            return;
 8182        }
 8183
 8184        let cursor = self.buffer.read(cx).read(cx).len();
 8185        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8186            s.select_ranges(vec![cursor..cursor])
 8187        });
 8188    }
 8189
 8190    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 8191        self.nav_history = nav_history;
 8192    }
 8193
 8194    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 8195        self.nav_history.as_ref()
 8196    }
 8197
 8198    fn push_to_nav_history(
 8199        &mut self,
 8200        cursor_anchor: Anchor,
 8201        new_position: Option<Point>,
 8202        cx: &mut ViewContext<Self>,
 8203    ) {
 8204        if let Some(nav_history) = self.nav_history.as_mut() {
 8205            let buffer = self.buffer.read(cx).read(cx);
 8206            let cursor_position = cursor_anchor.to_point(&buffer);
 8207            let scroll_state = self.scroll_manager.anchor();
 8208            let scroll_top_row = scroll_state.top_row(&buffer);
 8209            drop(buffer);
 8210
 8211            if let Some(new_position) = new_position {
 8212                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 8213                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 8214                    return;
 8215                }
 8216            }
 8217
 8218            nav_history.push(
 8219                Some(NavigationData {
 8220                    cursor_anchor,
 8221                    cursor_position,
 8222                    scroll_anchor: scroll_state,
 8223                    scroll_top_row,
 8224                }),
 8225                cx,
 8226            );
 8227        }
 8228    }
 8229
 8230    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 8231        let buffer = self.buffer.read(cx).snapshot(cx);
 8232        let mut selection = self.selections.first::<usize>(cx);
 8233        selection.set_head(buffer.len(), SelectionGoal::None);
 8234        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8235            s.select(vec![selection]);
 8236        });
 8237    }
 8238
 8239    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 8240        let end = self.buffer.read(cx).read(cx).len();
 8241        self.change_selections(None, cx, |s| {
 8242            s.select_ranges(vec![0..end]);
 8243        });
 8244    }
 8245
 8246    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 8247        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8248        let mut selections = self.selections.all::<Point>(cx);
 8249        let max_point = display_map.buffer_snapshot.max_point();
 8250        for selection in &mut selections {
 8251            let rows = selection.spanned_rows(true, &display_map);
 8252            selection.start = Point::new(rows.start.0, 0);
 8253            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
 8254            selection.reversed = false;
 8255        }
 8256        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8257            s.select(selections);
 8258        });
 8259    }
 8260
 8261    pub fn split_selection_into_lines(
 8262        &mut self,
 8263        _: &SplitSelectionIntoLines,
 8264        cx: &mut ViewContext<Self>,
 8265    ) {
 8266        let mut to_unfold = Vec::new();
 8267        let mut new_selection_ranges = Vec::new();
 8268        {
 8269            let selections = self.selections.all::<Point>(cx);
 8270            let buffer = self.buffer.read(cx).read(cx);
 8271            for selection in selections {
 8272                for row in selection.start.row..selection.end.row {
 8273                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
 8274                    new_selection_ranges.push(cursor..cursor);
 8275                }
 8276                new_selection_ranges.push(selection.end..selection.end);
 8277                to_unfold.push(selection.start..selection.end);
 8278            }
 8279        }
 8280        self.unfold_ranges(&to_unfold, true, true, cx);
 8281        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8282            s.select_ranges(new_selection_ranges);
 8283        });
 8284    }
 8285
 8286    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 8287        self.add_selection(true, cx);
 8288    }
 8289
 8290    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 8291        self.add_selection(false, cx);
 8292    }
 8293
 8294    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 8295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8296        let mut selections = self.selections.all::<Point>(cx);
 8297        let text_layout_details = self.text_layout_details(cx);
 8298        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 8299            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 8300            let range = oldest_selection.display_range(&display_map).sorted();
 8301
 8302            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 8303            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 8304            let positions = start_x.min(end_x)..start_x.max(end_x);
 8305
 8306            selections.clear();
 8307            let mut stack = Vec::new();
 8308            for row in range.start.row().0..=range.end.row().0 {
 8309                if let Some(selection) = self.selections.build_columnar_selection(
 8310                    &display_map,
 8311                    DisplayRow(row),
 8312                    &positions,
 8313                    oldest_selection.reversed,
 8314                    &text_layout_details,
 8315                ) {
 8316                    stack.push(selection.id);
 8317                    selections.push(selection);
 8318                }
 8319            }
 8320
 8321            if above {
 8322                stack.reverse();
 8323            }
 8324
 8325            AddSelectionsState { above, stack }
 8326        });
 8327
 8328        let last_added_selection = *state.stack.last().unwrap();
 8329        let mut new_selections = Vec::new();
 8330        if above == state.above {
 8331            let end_row = if above {
 8332                DisplayRow(0)
 8333            } else {
 8334                display_map.max_point().row()
 8335            };
 8336
 8337            'outer: for selection in selections {
 8338                if selection.id == last_added_selection {
 8339                    let range = selection.display_range(&display_map).sorted();
 8340                    debug_assert_eq!(range.start.row(), range.end.row());
 8341                    let mut row = range.start.row();
 8342                    let positions =
 8343                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 8344                            px(start)..px(end)
 8345                        } else {
 8346                            let start_x =
 8347                                display_map.x_for_display_point(range.start, &text_layout_details);
 8348                            let end_x =
 8349                                display_map.x_for_display_point(range.end, &text_layout_details);
 8350                            start_x.min(end_x)..start_x.max(end_x)
 8351                        };
 8352
 8353                    while row != end_row {
 8354                        if above {
 8355                            row.0 -= 1;
 8356                        } else {
 8357                            row.0 += 1;
 8358                        }
 8359
 8360                        if let Some(new_selection) = self.selections.build_columnar_selection(
 8361                            &display_map,
 8362                            row,
 8363                            &positions,
 8364                            selection.reversed,
 8365                            &text_layout_details,
 8366                        ) {
 8367                            state.stack.push(new_selection.id);
 8368                            if above {
 8369                                new_selections.push(new_selection);
 8370                                new_selections.push(selection);
 8371                            } else {
 8372                                new_selections.push(selection);
 8373                                new_selections.push(new_selection);
 8374                            }
 8375
 8376                            continue 'outer;
 8377                        }
 8378                    }
 8379                }
 8380
 8381                new_selections.push(selection);
 8382            }
 8383        } else {
 8384            new_selections = selections;
 8385            new_selections.retain(|s| s.id != last_added_selection);
 8386            state.stack.pop();
 8387        }
 8388
 8389        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8390            s.select(new_selections);
 8391        });
 8392        if state.stack.len() > 1 {
 8393            self.add_selections_state = Some(state);
 8394        }
 8395    }
 8396
 8397    pub fn select_next_match_internal(
 8398        &mut self,
 8399        display_map: &DisplaySnapshot,
 8400        replace_newest: bool,
 8401        autoscroll: Option<Autoscroll>,
 8402        cx: &mut ViewContext<Self>,
 8403    ) -> Result<()> {
 8404        fn select_next_match_ranges(
 8405            this: &mut Editor,
 8406            range: Range<usize>,
 8407            replace_newest: bool,
 8408            auto_scroll: Option<Autoscroll>,
 8409            cx: &mut ViewContext<Editor>,
 8410        ) {
 8411            this.unfold_ranges(&[range.clone()], false, true, cx);
 8412            this.change_selections(auto_scroll, cx, |s| {
 8413                if replace_newest {
 8414                    s.delete(s.newest_anchor().id);
 8415                }
 8416                s.insert_range(range.clone());
 8417            });
 8418        }
 8419
 8420        let buffer = &display_map.buffer_snapshot;
 8421        let mut selections = self.selections.all::<usize>(cx);
 8422        if let Some(mut select_next_state) = self.select_next_state.take() {
 8423            let query = &select_next_state.query;
 8424            if !select_next_state.done {
 8425                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 8426                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 8427                let mut next_selected_range = None;
 8428
 8429                let bytes_after_last_selection =
 8430                    buffer.bytes_in_range(last_selection.end..buffer.len());
 8431                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 8432                let query_matches = query
 8433                    .stream_find_iter(bytes_after_last_selection)
 8434                    .map(|result| (last_selection.end, result))
 8435                    .chain(
 8436                        query
 8437                            .stream_find_iter(bytes_before_first_selection)
 8438                            .map(|result| (0, result)),
 8439                    );
 8440
 8441                for (start_offset, query_match) in query_matches {
 8442                    let query_match = query_match.unwrap(); // can only fail due to I/O
 8443                    let offset_range =
 8444                        start_offset + query_match.start()..start_offset + query_match.end();
 8445                    let display_range = offset_range.start.to_display_point(display_map)
 8446                        ..offset_range.end.to_display_point(display_map);
 8447
 8448                    if !select_next_state.wordwise
 8449                        || (!movement::is_inside_word(display_map, display_range.start)
 8450                            && !movement::is_inside_word(display_map, display_range.end))
 8451                    {
 8452                        // TODO: This is n^2, because we might check all the selections
 8453                        if !selections
 8454                            .iter()
 8455                            .any(|selection| selection.range().overlaps(&offset_range))
 8456                        {
 8457                            next_selected_range = Some(offset_range);
 8458                            break;
 8459                        }
 8460                    }
 8461                }
 8462
 8463                if let Some(next_selected_range) = next_selected_range {
 8464                    select_next_match_ranges(
 8465                        self,
 8466                        next_selected_range,
 8467                        replace_newest,
 8468                        autoscroll,
 8469                        cx,
 8470                    );
 8471                } else {
 8472                    select_next_state.done = true;
 8473                }
 8474            }
 8475
 8476            self.select_next_state = Some(select_next_state);
 8477        } else {
 8478            let mut only_carets = true;
 8479            let mut same_text_selected = true;
 8480            let mut selected_text = None;
 8481
 8482            let mut selections_iter = selections.iter().peekable();
 8483            while let Some(selection) = selections_iter.next() {
 8484                if selection.start != selection.end {
 8485                    only_carets = false;
 8486                }
 8487
 8488                if same_text_selected {
 8489                    if selected_text.is_none() {
 8490                        selected_text =
 8491                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 8492                    }
 8493
 8494                    if let Some(next_selection) = selections_iter.peek() {
 8495                        if next_selection.range().len() == selection.range().len() {
 8496                            let next_selected_text = buffer
 8497                                .text_for_range(next_selection.range())
 8498                                .collect::<String>();
 8499                            if Some(next_selected_text) != selected_text {
 8500                                same_text_selected = false;
 8501                                selected_text = None;
 8502                            }
 8503                        } else {
 8504                            same_text_selected = false;
 8505                            selected_text = None;
 8506                        }
 8507                    }
 8508                }
 8509            }
 8510
 8511            if only_carets {
 8512                for selection in &mut selections {
 8513                    let word_range = movement::surrounding_word(
 8514                        display_map,
 8515                        selection.start.to_display_point(display_map),
 8516                    );
 8517                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
 8518                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
 8519                    selection.goal = SelectionGoal::None;
 8520                    selection.reversed = false;
 8521                    select_next_match_ranges(
 8522                        self,
 8523                        selection.start..selection.end,
 8524                        replace_newest,
 8525                        autoscroll,
 8526                        cx,
 8527                    );
 8528                }
 8529
 8530                if selections.len() == 1 {
 8531                    let selection = selections
 8532                        .last()
 8533                        .expect("ensured that there's only one selection");
 8534                    let query = buffer
 8535                        .text_for_range(selection.start..selection.end)
 8536                        .collect::<String>();
 8537                    let is_empty = query.is_empty();
 8538                    let select_state = SelectNextState {
 8539                        query: AhoCorasick::new(&[query])?,
 8540                        wordwise: true,
 8541                        done: is_empty,
 8542                    };
 8543                    self.select_next_state = Some(select_state);
 8544                } else {
 8545                    self.select_next_state = None;
 8546                }
 8547            } else if let Some(selected_text) = selected_text {
 8548                self.select_next_state = Some(SelectNextState {
 8549                    query: AhoCorasick::new(&[selected_text])?,
 8550                    wordwise: false,
 8551                    done: false,
 8552                });
 8553                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
 8554            }
 8555        }
 8556        Ok(())
 8557    }
 8558
 8559    pub fn select_all_matches(
 8560        &mut self,
 8561        _action: &SelectAllMatches,
 8562        cx: &mut ViewContext<Self>,
 8563    ) -> Result<()> {
 8564        self.push_to_selection_history();
 8565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8566
 8567        self.select_next_match_internal(&display_map, false, None, cx)?;
 8568        let Some(select_next_state) = self.select_next_state.as_mut() else {
 8569            return Ok(());
 8570        };
 8571        if select_next_state.done {
 8572            return Ok(());
 8573        }
 8574
 8575        let mut new_selections = self.selections.all::<usize>(cx);
 8576
 8577        let buffer = &display_map.buffer_snapshot;
 8578        let query_matches = select_next_state
 8579            .query
 8580            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
 8581
 8582        for query_match in query_matches {
 8583            let query_match = query_match.unwrap(); // can only fail due to I/O
 8584            let offset_range = query_match.start()..query_match.end();
 8585            let display_range = offset_range.start.to_display_point(&display_map)
 8586                ..offset_range.end.to_display_point(&display_map);
 8587
 8588            if !select_next_state.wordwise
 8589                || (!movement::is_inside_word(&display_map, display_range.start)
 8590                    && !movement::is_inside_word(&display_map, display_range.end))
 8591            {
 8592                self.selections.change_with(cx, |selections| {
 8593                    new_selections.push(Selection {
 8594                        id: selections.new_selection_id(),
 8595                        start: offset_range.start,
 8596                        end: offset_range.end,
 8597                        reversed: false,
 8598                        goal: SelectionGoal::None,
 8599                    });
 8600                });
 8601            }
 8602        }
 8603
 8604        new_selections.sort_by_key(|selection| selection.start);
 8605        let mut ix = 0;
 8606        while ix + 1 < new_selections.len() {
 8607            let current_selection = &new_selections[ix];
 8608            let next_selection = &new_selections[ix + 1];
 8609            if current_selection.range().overlaps(&next_selection.range()) {
 8610                if current_selection.id < next_selection.id {
 8611                    new_selections.remove(ix + 1);
 8612                } else {
 8613                    new_selections.remove(ix);
 8614                }
 8615            } else {
 8616                ix += 1;
 8617            }
 8618        }
 8619
 8620        select_next_state.done = true;
 8621        self.unfold_ranges(
 8622            &new_selections
 8623                .iter()
 8624                .map(|selection| selection.range())
 8625                .collect::<Vec<_>>(),
 8626            false,
 8627            false,
 8628            cx,
 8629        );
 8630        self.change_selections(Some(Autoscroll::fit()), cx, |selections| {
 8631            selections.select(new_selections)
 8632        });
 8633
 8634        Ok(())
 8635    }
 8636
 8637    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
 8638        self.push_to_selection_history();
 8639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8640        self.select_next_match_internal(
 8641            &display_map,
 8642            action.replace_newest,
 8643            Some(Autoscroll::newest()),
 8644            cx,
 8645        )?;
 8646        Ok(())
 8647    }
 8648
 8649    pub fn select_previous(
 8650        &mut self,
 8651        action: &SelectPrevious,
 8652        cx: &mut ViewContext<Self>,
 8653    ) -> Result<()> {
 8654        self.push_to_selection_history();
 8655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8656        let buffer = &display_map.buffer_snapshot;
 8657        let mut selections = self.selections.all::<usize>(cx);
 8658        if let Some(mut select_prev_state) = self.select_prev_state.take() {
 8659            let query = &select_prev_state.query;
 8660            if !select_prev_state.done {
 8661                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 8662                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 8663                let mut next_selected_range = None;
 8664                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
 8665                let bytes_before_last_selection =
 8666                    buffer.reversed_bytes_in_range(0..last_selection.start);
 8667                let bytes_after_first_selection =
 8668                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
 8669                let query_matches = query
 8670                    .stream_find_iter(bytes_before_last_selection)
 8671                    .map(|result| (last_selection.start, result))
 8672                    .chain(
 8673                        query
 8674                            .stream_find_iter(bytes_after_first_selection)
 8675                            .map(|result| (buffer.len(), result)),
 8676                    );
 8677                for (end_offset, query_match) in query_matches {
 8678                    let query_match = query_match.unwrap(); // can only fail due to I/O
 8679                    let offset_range =
 8680                        end_offset - query_match.end()..end_offset - query_match.start();
 8681                    let display_range = offset_range.start.to_display_point(&display_map)
 8682                        ..offset_range.end.to_display_point(&display_map);
 8683
 8684                    if !select_prev_state.wordwise
 8685                        || (!movement::is_inside_word(&display_map, display_range.start)
 8686                            && !movement::is_inside_word(&display_map, display_range.end))
 8687                    {
 8688                        next_selected_range = Some(offset_range);
 8689                        break;
 8690                    }
 8691                }
 8692
 8693                if let Some(next_selected_range) = next_selected_range {
 8694                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
 8695                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 8696                        if action.replace_newest {
 8697                            s.delete(s.newest_anchor().id);
 8698                        }
 8699                        s.insert_range(next_selected_range);
 8700                    });
 8701                } else {
 8702                    select_prev_state.done = true;
 8703                }
 8704            }
 8705
 8706            self.select_prev_state = Some(select_prev_state);
 8707        } else {
 8708            let mut only_carets = true;
 8709            let mut same_text_selected = true;
 8710            let mut selected_text = None;
 8711
 8712            let mut selections_iter = selections.iter().peekable();
 8713            while let Some(selection) = selections_iter.next() {
 8714                if selection.start != selection.end {
 8715                    only_carets = false;
 8716                }
 8717
 8718                if same_text_selected {
 8719                    if selected_text.is_none() {
 8720                        selected_text =
 8721                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 8722                    }
 8723
 8724                    if let Some(next_selection) = selections_iter.peek() {
 8725                        if next_selection.range().len() == selection.range().len() {
 8726                            let next_selected_text = buffer
 8727                                .text_for_range(next_selection.range())
 8728                                .collect::<String>();
 8729                            if Some(next_selected_text) != selected_text {
 8730                                same_text_selected = false;
 8731                                selected_text = None;
 8732                            }
 8733                        } else {
 8734                            same_text_selected = false;
 8735                            selected_text = None;
 8736                        }
 8737                    }
 8738                }
 8739            }
 8740
 8741            if only_carets {
 8742                for selection in &mut selections {
 8743                    let word_range = movement::surrounding_word(
 8744                        &display_map,
 8745                        selection.start.to_display_point(&display_map),
 8746                    );
 8747                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 8748                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 8749                    selection.goal = SelectionGoal::None;
 8750                    selection.reversed = false;
 8751                }
 8752                if selections.len() == 1 {
 8753                    let selection = selections
 8754                        .last()
 8755                        .expect("ensured that there's only one selection");
 8756                    let query = buffer
 8757                        .text_for_range(selection.start..selection.end)
 8758                        .collect::<String>();
 8759                    let is_empty = query.is_empty();
 8760                    let select_state = SelectNextState {
 8761                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
 8762                        wordwise: true,
 8763                        done: is_empty,
 8764                    };
 8765                    self.select_prev_state = Some(select_state);
 8766                } else {
 8767                    self.select_prev_state = None;
 8768                }
 8769
 8770                self.unfold_ranges(
 8771                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
 8772                    false,
 8773                    true,
 8774                    cx,
 8775                );
 8776                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 8777                    s.select(selections);
 8778                });
 8779            } else if let Some(selected_text) = selected_text {
 8780                self.select_prev_state = Some(SelectNextState {
 8781                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
 8782                    wordwise: false,
 8783                    done: false,
 8784                });
 8785                self.select_previous(action, cx)?;
 8786            }
 8787        }
 8788        Ok(())
 8789    }
 8790
 8791    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
 8792        if self.read_only(cx) {
 8793            return;
 8794        }
 8795        let text_layout_details = &self.text_layout_details(cx);
 8796        self.transact(cx, |this, cx| {
 8797            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8798            let mut edits = Vec::new();
 8799            let mut selection_edit_ranges = Vec::new();
 8800            let mut last_toggled_row = None;
 8801            let snapshot = this.buffer.read(cx).read(cx);
 8802            let empty_str: Arc<str> = Arc::default();
 8803            let mut suffixes_inserted = Vec::new();
 8804            let ignore_indent = action.ignore_indent;
 8805
 8806            fn comment_prefix_range(
 8807                snapshot: &MultiBufferSnapshot,
 8808                row: MultiBufferRow,
 8809                comment_prefix: &str,
 8810                comment_prefix_whitespace: &str,
 8811                ignore_indent: bool,
 8812            ) -> Range<Point> {
 8813                let indent_size = if ignore_indent {
 8814                    0
 8815                } else {
 8816                    snapshot.indent_size_for_line(row).len
 8817                };
 8818
 8819                let start = Point::new(row.0, indent_size);
 8820
 8821                let mut line_bytes = snapshot
 8822                    .bytes_in_range(start..snapshot.max_point())
 8823                    .flatten()
 8824                    .copied();
 8825
 8826                // If this line currently begins with the line comment prefix, then record
 8827                // the range containing the prefix.
 8828                if line_bytes
 8829                    .by_ref()
 8830                    .take(comment_prefix.len())
 8831                    .eq(comment_prefix.bytes())
 8832                {
 8833                    // Include any whitespace that matches the comment prefix.
 8834                    let matching_whitespace_len = line_bytes
 8835                        .zip(comment_prefix_whitespace.bytes())
 8836                        .take_while(|(a, b)| a == b)
 8837                        .count() as u32;
 8838                    let end = Point::new(
 8839                        start.row,
 8840                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
 8841                    );
 8842                    start..end
 8843                } else {
 8844                    start..start
 8845                }
 8846            }
 8847
 8848            fn comment_suffix_range(
 8849                snapshot: &MultiBufferSnapshot,
 8850                row: MultiBufferRow,
 8851                comment_suffix: &str,
 8852                comment_suffix_has_leading_space: bool,
 8853            ) -> Range<Point> {
 8854                let end = Point::new(row.0, snapshot.line_len(row));
 8855                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
 8856
 8857                let mut line_end_bytes = snapshot
 8858                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
 8859                    .flatten()
 8860                    .copied();
 8861
 8862                let leading_space_len = if suffix_start_column > 0
 8863                    && line_end_bytes.next() == Some(b' ')
 8864                    && comment_suffix_has_leading_space
 8865                {
 8866                    1
 8867                } else {
 8868                    0
 8869                };
 8870
 8871                // If this line currently begins with the line comment prefix, then record
 8872                // the range containing the prefix.
 8873                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
 8874                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
 8875                    start..end
 8876                } else {
 8877                    end..end
 8878                }
 8879            }
 8880
 8881            // TODO: Handle selections that cross excerpts
 8882            for selection in &mut selections {
 8883                let start_column = snapshot
 8884                    .indent_size_for_line(MultiBufferRow(selection.start.row))
 8885                    .len;
 8886                let language = if let Some(language) =
 8887                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
 8888                {
 8889                    language
 8890                } else {
 8891                    continue;
 8892                };
 8893
 8894                selection_edit_ranges.clear();
 8895
 8896                // If multiple selections contain a given row, avoid processing that
 8897                // row more than once.
 8898                let mut start_row = MultiBufferRow(selection.start.row);
 8899                if last_toggled_row == Some(start_row) {
 8900                    start_row = start_row.next_row();
 8901                }
 8902                let end_row =
 8903                    if selection.end.row > selection.start.row && selection.end.column == 0 {
 8904                        MultiBufferRow(selection.end.row - 1)
 8905                    } else {
 8906                        MultiBufferRow(selection.end.row)
 8907                    };
 8908                last_toggled_row = Some(end_row);
 8909
 8910                if start_row > end_row {
 8911                    continue;
 8912                }
 8913
 8914                // If the language has line comments, toggle those.
 8915                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
 8916
 8917                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
 8918                if ignore_indent {
 8919                    full_comment_prefixes = full_comment_prefixes
 8920                        .into_iter()
 8921                        .map(|s| Arc::from(s.trim_end()))
 8922                        .collect();
 8923                }
 8924
 8925                if !full_comment_prefixes.is_empty() {
 8926                    let first_prefix = full_comment_prefixes
 8927                        .first()
 8928                        .expect("prefixes is non-empty");
 8929                    let prefix_trimmed_lengths = full_comment_prefixes
 8930                        .iter()
 8931                        .map(|p| p.trim_end_matches(' ').len())
 8932                        .collect::<SmallVec<[usize; 4]>>();
 8933
 8934                    let mut all_selection_lines_are_comments = true;
 8935
 8936                    for row in start_row.0..=end_row.0 {
 8937                        let row = MultiBufferRow(row);
 8938                        if start_row < end_row && snapshot.is_line_blank(row) {
 8939                            continue;
 8940                        }
 8941
 8942                        let prefix_range = full_comment_prefixes
 8943                            .iter()
 8944                            .zip(prefix_trimmed_lengths.iter().copied())
 8945                            .map(|(prefix, trimmed_prefix_len)| {
 8946                                comment_prefix_range(
 8947                                    snapshot.deref(),
 8948                                    row,
 8949                                    &prefix[..trimmed_prefix_len],
 8950                                    &prefix[trimmed_prefix_len..],
 8951                                    ignore_indent,
 8952                                )
 8953                            })
 8954                            .max_by_key(|range| range.end.column - range.start.column)
 8955                            .expect("prefixes is non-empty");
 8956
 8957                        if prefix_range.is_empty() {
 8958                            all_selection_lines_are_comments = false;
 8959                        }
 8960
 8961                        selection_edit_ranges.push(prefix_range);
 8962                    }
 8963
 8964                    if all_selection_lines_are_comments {
 8965                        edits.extend(
 8966                            selection_edit_ranges
 8967                                .iter()
 8968                                .cloned()
 8969                                .map(|range| (range, empty_str.clone())),
 8970                        );
 8971                    } else {
 8972                        let min_column = selection_edit_ranges
 8973                            .iter()
 8974                            .map(|range| range.start.column)
 8975                            .min()
 8976                            .unwrap_or(0);
 8977                        edits.extend(selection_edit_ranges.iter().map(|range| {
 8978                            let position = Point::new(range.start.row, min_column);
 8979                            (position..position, first_prefix.clone())
 8980                        }));
 8981                    }
 8982                } else if let Some((full_comment_prefix, comment_suffix)) =
 8983                    language.block_comment_delimiters()
 8984                {
 8985                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 8986                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 8987                    let prefix_range = comment_prefix_range(
 8988                        snapshot.deref(),
 8989                        start_row,
 8990                        comment_prefix,
 8991                        comment_prefix_whitespace,
 8992                        ignore_indent,
 8993                    );
 8994                    let suffix_range = comment_suffix_range(
 8995                        snapshot.deref(),
 8996                        end_row,
 8997                        comment_suffix.trim_start_matches(' '),
 8998                        comment_suffix.starts_with(' '),
 8999                    );
 9000
 9001                    if prefix_range.is_empty() || suffix_range.is_empty() {
 9002                        edits.push((
 9003                            prefix_range.start..prefix_range.start,
 9004                            full_comment_prefix.clone(),
 9005                        ));
 9006                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
 9007                        suffixes_inserted.push((end_row, comment_suffix.len()));
 9008                    } else {
 9009                        edits.push((prefix_range, empty_str.clone()));
 9010                        edits.push((suffix_range, empty_str.clone()));
 9011                    }
 9012                } else {
 9013                    continue;
 9014                }
 9015            }
 9016
 9017            drop(snapshot);
 9018            this.buffer.update(cx, |buffer, cx| {
 9019                buffer.edit(edits, None, cx);
 9020            });
 9021
 9022            // Adjust selections so that they end before any comment suffixes that
 9023            // were inserted.
 9024            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
 9025            let mut selections = this.selections.all::<Point>(cx);
 9026            let snapshot = this.buffer.read(cx).read(cx);
 9027            for selection in &mut selections {
 9028                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
 9029                    match row.cmp(&MultiBufferRow(selection.end.row)) {
 9030                        Ordering::Less => {
 9031                            suffixes_inserted.next();
 9032                            continue;
 9033                        }
 9034                        Ordering::Greater => break,
 9035                        Ordering::Equal => {
 9036                            if selection.end.column == snapshot.line_len(row) {
 9037                                if selection.is_empty() {
 9038                                    selection.start.column -= suffix_len as u32;
 9039                                }
 9040                                selection.end.column -= suffix_len as u32;
 9041                            }
 9042                            break;
 9043                        }
 9044                    }
 9045                }
 9046            }
 9047
 9048            drop(snapshot);
 9049            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 9050
 9051            let selections = this.selections.all::<Point>(cx);
 9052            let selections_on_single_row = selections.windows(2).all(|selections| {
 9053                selections[0].start.row == selections[1].start.row
 9054                    && selections[0].end.row == selections[1].end.row
 9055                    && selections[0].start.row == selections[0].end.row
 9056            });
 9057            let selections_selecting = selections
 9058                .iter()
 9059                .any(|selection| selection.start != selection.end);
 9060            let advance_downwards = action.advance_downwards
 9061                && selections_on_single_row
 9062                && !selections_selecting
 9063                && !matches!(this.mode, EditorMode::SingleLine { .. });
 9064
 9065            if advance_downwards {
 9066                let snapshot = this.buffer.read(cx).snapshot(cx);
 9067
 9068                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9069                    s.move_cursors_with(|display_snapshot, display_point, _| {
 9070                        let mut point = display_point.to_point(display_snapshot);
 9071                        point.row += 1;
 9072                        point = snapshot.clip_point(point, Bias::Left);
 9073                        let display_point = point.to_display_point(display_snapshot);
 9074                        let goal = SelectionGoal::HorizontalPosition(
 9075                            display_snapshot
 9076                                .x_for_display_point(display_point, text_layout_details)
 9077                                .into(),
 9078                        );
 9079                        (display_point, goal)
 9080                    })
 9081                });
 9082            }
 9083        });
 9084    }
 9085
 9086    pub fn select_enclosing_symbol(
 9087        &mut self,
 9088        _: &SelectEnclosingSymbol,
 9089        cx: &mut ViewContext<Self>,
 9090    ) {
 9091        let buffer = self.buffer.read(cx).snapshot(cx);
 9092        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 9093
 9094        fn update_selection(
 9095            selection: &Selection<usize>,
 9096            buffer_snap: &MultiBufferSnapshot,
 9097        ) -> Option<Selection<usize>> {
 9098            let cursor = selection.head();
 9099            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
 9100            for symbol in symbols.iter().rev() {
 9101                let start = symbol.range.start.to_offset(buffer_snap);
 9102                let end = symbol.range.end.to_offset(buffer_snap);
 9103                let new_range = start..end;
 9104                if start < selection.start || end > selection.end {
 9105                    return Some(Selection {
 9106                        id: selection.id,
 9107                        start: new_range.start,
 9108                        end: new_range.end,
 9109                        goal: SelectionGoal::None,
 9110                        reversed: selection.reversed,
 9111                    });
 9112                }
 9113            }
 9114            None
 9115        }
 9116
 9117        let mut selected_larger_symbol = false;
 9118        let new_selections = old_selections
 9119            .iter()
 9120            .map(|selection| match update_selection(selection, &buffer) {
 9121                Some(new_selection) => {
 9122                    if new_selection.range() != selection.range() {
 9123                        selected_larger_symbol = true;
 9124                    }
 9125                    new_selection
 9126                }
 9127                None => selection.clone(),
 9128            })
 9129            .collect::<Vec<_>>();
 9130
 9131        if selected_larger_symbol {
 9132            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9133                s.select(new_selections);
 9134            });
 9135        }
 9136    }
 9137
 9138    pub fn select_larger_syntax_node(
 9139        &mut self,
 9140        _: &SelectLargerSyntaxNode,
 9141        cx: &mut ViewContext<Self>,
 9142    ) {
 9143        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9144        let buffer = self.buffer.read(cx).snapshot(cx);
 9145        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 9146
 9147        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 9148        let mut selected_larger_node = false;
 9149        let new_selections = old_selections
 9150            .iter()
 9151            .map(|selection| {
 9152                let old_range = selection.start..selection.end;
 9153                let mut new_range = old_range.clone();
 9154                while let Some(containing_range) =
 9155                    buffer.range_for_syntax_ancestor(new_range.clone())
 9156                {
 9157                    new_range = containing_range;
 9158                    if !display_map.intersects_fold(new_range.start)
 9159                        && !display_map.intersects_fold(new_range.end)
 9160                    {
 9161                        break;
 9162                    }
 9163                }
 9164
 9165                selected_larger_node |= new_range != old_range;
 9166                Selection {
 9167                    id: selection.id,
 9168                    start: new_range.start,
 9169                    end: new_range.end,
 9170                    goal: SelectionGoal::None,
 9171                    reversed: selection.reversed,
 9172                }
 9173            })
 9174            .collect::<Vec<_>>();
 9175
 9176        if selected_larger_node {
 9177            stack.push(old_selections);
 9178            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9179                s.select(new_selections);
 9180            });
 9181        }
 9182        self.select_larger_syntax_node_stack = stack;
 9183    }
 9184
 9185    pub fn select_smaller_syntax_node(
 9186        &mut self,
 9187        _: &SelectSmallerSyntaxNode,
 9188        cx: &mut ViewContext<Self>,
 9189    ) {
 9190        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 9191        if let Some(selections) = stack.pop() {
 9192            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9193                s.select(selections.to_vec());
 9194            });
 9195        }
 9196        self.select_larger_syntax_node_stack = stack;
 9197    }
 9198
 9199    fn refresh_runnables(&mut self, cx: &mut ViewContext<Self>) -> Task<()> {
 9200        if !EditorSettings::get_global(cx).gutter.runnables {
 9201            self.clear_tasks();
 9202            return Task::ready(());
 9203        }
 9204        let project = self.project.as_ref().map(Model::downgrade);
 9205        cx.spawn(|this, mut cx| async move {
 9206            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
 9207            let Some(project) = project.and_then(|p| p.upgrade()) else {
 9208                return;
 9209            };
 9210            let Ok(display_snapshot) = this.update(&mut cx, |this, cx| {
 9211                this.display_map.update(cx, |map, cx| map.snapshot(cx))
 9212            }) else {
 9213                return;
 9214            };
 9215
 9216            let hide_runnables = project
 9217                .update(&mut cx, |project, cx| {
 9218                    // Do not display any test indicators in non-dev server remote projects.
 9219                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
 9220                })
 9221                .unwrap_or(true);
 9222            if hide_runnables {
 9223                return;
 9224            }
 9225            let new_rows =
 9226                cx.background_executor()
 9227                    .spawn({
 9228                        let snapshot = display_snapshot.clone();
 9229                        async move {
 9230                            Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
 9231                        }
 9232                    })
 9233                    .await;
 9234            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
 9235
 9236            this.update(&mut cx, |this, _| {
 9237                this.clear_tasks();
 9238                for (key, value) in rows {
 9239                    this.insert_tasks(key, value);
 9240                }
 9241            })
 9242            .ok();
 9243        })
 9244    }
 9245    fn fetch_runnable_ranges(
 9246        snapshot: &DisplaySnapshot,
 9247        range: Range<Anchor>,
 9248    ) -> Vec<language::RunnableRange> {
 9249        snapshot.buffer_snapshot.runnable_ranges(range).collect()
 9250    }
 9251
 9252    fn runnable_rows(
 9253        project: Model<Project>,
 9254        snapshot: DisplaySnapshot,
 9255        runnable_ranges: Vec<RunnableRange>,
 9256        mut cx: AsyncWindowContext,
 9257    ) -> Vec<((BufferId, u32), RunnableTasks)> {
 9258        runnable_ranges
 9259            .into_iter()
 9260            .filter_map(|mut runnable| {
 9261                let tasks = cx
 9262                    .update(|cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
 9263                    .ok()?;
 9264                if tasks.is_empty() {
 9265                    return None;
 9266                }
 9267
 9268                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
 9269
 9270                let row = snapshot
 9271                    .buffer_snapshot
 9272                    .buffer_line_for_row(MultiBufferRow(point.row))?
 9273                    .1
 9274                    .start
 9275                    .row;
 9276
 9277                let context_range =
 9278                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
 9279                Some((
 9280                    (runnable.buffer_id, row),
 9281                    RunnableTasks {
 9282                        templates: tasks,
 9283                        offset: MultiBufferOffset(runnable.run_range.start),
 9284                        context_range,
 9285                        column: point.column,
 9286                        extra_variables: runnable.extra_captures,
 9287                    },
 9288                ))
 9289            })
 9290            .collect()
 9291    }
 9292
 9293    fn templates_with_tags(
 9294        project: &Model<Project>,
 9295        runnable: &mut Runnable,
 9296        cx: &WindowContext<'_>,
 9297    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
 9298        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
 9299            let (worktree_id, file) = project
 9300                .buffer_for_id(runnable.buffer, cx)
 9301                .and_then(|buffer| buffer.read(cx).file())
 9302                .map(|file| (file.worktree_id(cx), file.clone()))
 9303                .unzip();
 9304
 9305            (
 9306                project.task_store().read(cx).task_inventory().cloned(),
 9307                worktree_id,
 9308                file,
 9309            )
 9310        });
 9311
 9312        let tags = mem::take(&mut runnable.tags);
 9313        let mut tags: Vec<_> = tags
 9314            .into_iter()
 9315            .flat_map(|tag| {
 9316                let tag = tag.0.clone();
 9317                inventory
 9318                    .as_ref()
 9319                    .into_iter()
 9320                    .flat_map(|inventory| {
 9321                        inventory.read(cx).list_tasks(
 9322                            file.clone(),
 9323                            Some(runnable.language.clone()),
 9324                            worktree_id,
 9325                            cx,
 9326                        )
 9327                    })
 9328                    .filter(move |(_, template)| {
 9329                        template.tags.iter().any(|source_tag| source_tag == &tag)
 9330                    })
 9331            })
 9332            .sorted_by_key(|(kind, _)| kind.to_owned())
 9333            .collect();
 9334        if let Some((leading_tag_source, _)) = tags.first() {
 9335            // Strongest source wins; if we have worktree tag binding, prefer that to
 9336            // global and language bindings;
 9337            // if we have a global binding, prefer that to language binding.
 9338            let first_mismatch = tags
 9339                .iter()
 9340                .position(|(tag_source, _)| tag_source != leading_tag_source);
 9341            if let Some(index) = first_mismatch {
 9342                tags.truncate(index);
 9343            }
 9344        }
 9345
 9346        tags
 9347    }
 9348
 9349    pub fn move_to_enclosing_bracket(
 9350        &mut self,
 9351        _: &MoveToEnclosingBracket,
 9352        cx: &mut ViewContext<Self>,
 9353    ) {
 9354        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9355            s.move_offsets_with(|snapshot, selection| {
 9356                let Some(enclosing_bracket_ranges) =
 9357                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
 9358                else {
 9359                    return;
 9360                };
 9361
 9362                let mut best_length = usize::MAX;
 9363                let mut best_inside = false;
 9364                let mut best_in_bracket_range = false;
 9365                let mut best_destination = None;
 9366                for (open, close) in enclosing_bracket_ranges {
 9367                    let close = close.to_inclusive();
 9368                    let length = close.end() - open.start;
 9369                    let inside = selection.start >= open.end && selection.end <= *close.start();
 9370                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
 9371                        || close.contains(&selection.head());
 9372
 9373                    // If best is next to a bracket and current isn't, skip
 9374                    if !in_bracket_range && best_in_bracket_range {
 9375                        continue;
 9376                    }
 9377
 9378                    // Prefer smaller lengths unless best is inside and current isn't
 9379                    if length > best_length && (best_inside || !inside) {
 9380                        continue;
 9381                    }
 9382
 9383                    best_length = length;
 9384                    best_inside = inside;
 9385                    best_in_bracket_range = in_bracket_range;
 9386                    best_destination = Some(
 9387                        if close.contains(&selection.start) && close.contains(&selection.end) {
 9388                            if inside {
 9389                                open.end
 9390                            } else {
 9391                                open.start
 9392                            }
 9393                        } else if inside {
 9394                            *close.start()
 9395                        } else {
 9396                            *close.end()
 9397                        },
 9398                    );
 9399                }
 9400
 9401                if let Some(destination) = best_destination {
 9402                    selection.collapse_to(destination, SelectionGoal::None);
 9403                }
 9404            })
 9405        });
 9406    }
 9407
 9408    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 9409        self.end_selection(cx);
 9410        self.selection_history.mode = SelectionHistoryMode::Undoing;
 9411        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 9412            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 9413            self.select_next_state = entry.select_next_state;
 9414            self.select_prev_state = entry.select_prev_state;
 9415            self.add_selections_state = entry.add_selections_state;
 9416            self.request_autoscroll(Autoscroll::newest(), cx);
 9417        }
 9418        self.selection_history.mode = SelectionHistoryMode::Normal;
 9419    }
 9420
 9421    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 9422        self.end_selection(cx);
 9423        self.selection_history.mode = SelectionHistoryMode::Redoing;
 9424        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 9425            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 9426            self.select_next_state = entry.select_next_state;
 9427            self.select_prev_state = entry.select_prev_state;
 9428            self.add_selections_state = entry.add_selections_state;
 9429            self.request_autoscroll(Autoscroll::newest(), cx);
 9430        }
 9431        self.selection_history.mode = SelectionHistoryMode::Normal;
 9432    }
 9433
 9434    pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext<Self>) {
 9435        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
 9436    }
 9437
 9438    pub fn expand_excerpts_down(
 9439        &mut self,
 9440        action: &ExpandExcerptsDown,
 9441        cx: &mut ViewContext<Self>,
 9442    ) {
 9443        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
 9444    }
 9445
 9446    pub fn expand_excerpts_up(&mut self, action: &ExpandExcerptsUp, cx: &mut ViewContext<Self>) {
 9447        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
 9448    }
 9449
 9450    pub fn expand_excerpts_for_direction(
 9451        &mut self,
 9452        lines: u32,
 9453        direction: ExpandExcerptDirection,
 9454        cx: &mut ViewContext<Self>,
 9455    ) {
 9456        let selections = self.selections.disjoint_anchors();
 9457
 9458        let lines = if lines == 0 {
 9459            EditorSettings::get_global(cx).expand_excerpt_lines
 9460        } else {
 9461            lines
 9462        };
 9463
 9464        self.buffer.update(cx, |buffer, cx| {
 9465            buffer.expand_excerpts(
 9466                selections
 9467                    .iter()
 9468                    .map(|selection| selection.head().excerpt_id)
 9469                    .dedup(),
 9470                lines,
 9471                direction,
 9472                cx,
 9473            )
 9474        })
 9475    }
 9476
 9477    pub fn expand_excerpt(
 9478        &mut self,
 9479        excerpt: ExcerptId,
 9480        direction: ExpandExcerptDirection,
 9481        cx: &mut ViewContext<Self>,
 9482    ) {
 9483        let lines = EditorSettings::get_global(cx).expand_excerpt_lines;
 9484        self.buffer.update(cx, |buffer, cx| {
 9485            buffer.expand_excerpts([excerpt], lines, direction, cx)
 9486        })
 9487    }
 9488
 9489    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
 9490        self.go_to_diagnostic_impl(Direction::Next, cx)
 9491    }
 9492
 9493    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 9494        self.go_to_diagnostic_impl(Direction::Prev, cx)
 9495    }
 9496
 9497    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 9498        let buffer = self.buffer.read(cx).snapshot(cx);
 9499        let selection = self.selections.newest::<usize>(cx);
 9500
 9501        // If there is an active Diagnostic Popover jump to its diagnostic instead.
 9502        if direction == Direction::Next {
 9503            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
 9504                let (group_id, jump_to) = popover.activation_info();
 9505                if self.activate_diagnostics(group_id, cx) {
 9506                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9507                        let mut new_selection = s.newest_anchor().clone();
 9508                        new_selection.collapse_to(jump_to, SelectionGoal::None);
 9509                        s.select_anchors(vec![new_selection.clone()]);
 9510                    });
 9511                }
 9512                return;
 9513            }
 9514        }
 9515
 9516        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 9517            active_diagnostics
 9518                .primary_range
 9519                .to_offset(&buffer)
 9520                .to_inclusive()
 9521        });
 9522        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 9523            if active_primary_range.contains(&selection.head()) {
 9524                *active_primary_range.start()
 9525            } else {
 9526                selection.head()
 9527            }
 9528        } else {
 9529            selection.head()
 9530        };
 9531        let snapshot = self.snapshot(cx);
 9532        loop {
 9533            let diagnostics = if direction == Direction::Prev {
 9534                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 9535            } else {
 9536                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 9537            }
 9538            .filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
 9539            let group = diagnostics
 9540                // relies on diagnostics_in_range to return diagnostics with the same starting range to
 9541                // be sorted in a stable way
 9542                // skip until we are at current active diagnostic, if it exists
 9543                .skip_while(|entry| {
 9544                    (match direction {
 9545                        Direction::Prev => entry.range.start >= search_start,
 9546                        Direction::Next => entry.range.start <= search_start,
 9547                    }) && self
 9548                        .active_diagnostics
 9549                        .as_ref()
 9550                        .is_some_and(|a| a.group_id != entry.diagnostic.group_id)
 9551                })
 9552                .find_map(|entry| {
 9553                    if entry.diagnostic.is_primary
 9554                        && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 9555                        && !entry.range.is_empty()
 9556                        // if we match with the active diagnostic, skip it
 9557                        && Some(entry.diagnostic.group_id)
 9558                            != self.active_diagnostics.as_ref().map(|d| d.group_id)
 9559                    {
 9560                        Some((entry.range, entry.diagnostic.group_id))
 9561                    } else {
 9562                        None
 9563                    }
 9564                });
 9565
 9566            if let Some((primary_range, group_id)) = group {
 9567                if self.activate_diagnostics(group_id, cx) {
 9568                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9569                        s.select(vec![Selection {
 9570                            id: selection.id,
 9571                            start: primary_range.start,
 9572                            end: primary_range.start,
 9573                            reversed: false,
 9574                            goal: SelectionGoal::None,
 9575                        }]);
 9576                    });
 9577                }
 9578                break;
 9579            } else {
 9580                // Cycle around to the start of the buffer, potentially moving back to the start of
 9581                // the currently active diagnostic.
 9582                active_primary_range.take();
 9583                if direction == Direction::Prev {
 9584                    if search_start == buffer.len() {
 9585                        break;
 9586                    } else {
 9587                        search_start = buffer.len();
 9588                    }
 9589                } else if search_start == 0 {
 9590                    break;
 9591                } else {
 9592                    search_start = 0;
 9593                }
 9594            }
 9595        }
 9596    }
 9597
 9598    fn go_to_next_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
 9599        let snapshot = self
 9600            .display_map
 9601            .update(cx, |display_map, cx| display_map.snapshot(cx));
 9602        let selection = self.selections.newest::<Point>(cx);
 9603        self.go_to_hunk_after_position(&snapshot, selection.head(), cx);
 9604    }
 9605
 9606    fn go_to_hunk_after_position(
 9607        &mut self,
 9608        snapshot: &DisplaySnapshot,
 9609        position: Point,
 9610        cx: &mut ViewContext<'_, Editor>,
 9611    ) -> Option<MultiBufferDiffHunk> {
 9612        if let Some(hunk) = self.go_to_next_hunk_in_direction(
 9613            snapshot,
 9614            position,
 9615            false,
 9616            snapshot
 9617                .buffer_snapshot
 9618                .git_diff_hunks_in_range(MultiBufferRow(position.row + 1)..MultiBufferRow::MAX),
 9619            cx,
 9620        ) {
 9621            return Some(hunk);
 9622        }
 9623
 9624        let wrapped_point = Point::zero();
 9625        self.go_to_next_hunk_in_direction(
 9626            snapshot,
 9627            wrapped_point,
 9628            true,
 9629            snapshot.buffer_snapshot.git_diff_hunks_in_range(
 9630                MultiBufferRow(wrapped_point.row + 1)..MultiBufferRow::MAX,
 9631            ),
 9632            cx,
 9633        )
 9634    }
 9635
 9636    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
 9637        let snapshot = self
 9638            .display_map
 9639            .update(cx, |display_map, cx| display_map.snapshot(cx));
 9640        let selection = self.selections.newest::<Point>(cx);
 9641
 9642        self.go_to_hunk_before_position(&snapshot, selection.head(), cx);
 9643    }
 9644
 9645    fn go_to_hunk_before_position(
 9646        &mut self,
 9647        snapshot: &DisplaySnapshot,
 9648        position: Point,
 9649        cx: &mut ViewContext<'_, Editor>,
 9650    ) -> Option<MultiBufferDiffHunk> {
 9651        if let Some(hunk) = self.go_to_next_hunk_in_direction(
 9652            snapshot,
 9653            position,
 9654            false,
 9655            snapshot
 9656                .buffer_snapshot
 9657                .git_diff_hunks_in_range_rev(MultiBufferRow(0)..MultiBufferRow(position.row)),
 9658            cx,
 9659        ) {
 9660            return Some(hunk);
 9661        }
 9662
 9663        let wrapped_point = snapshot.buffer_snapshot.max_point();
 9664        self.go_to_next_hunk_in_direction(
 9665            snapshot,
 9666            wrapped_point,
 9667            true,
 9668            snapshot
 9669                .buffer_snapshot
 9670                .git_diff_hunks_in_range_rev(MultiBufferRow(0)..MultiBufferRow(wrapped_point.row)),
 9671            cx,
 9672        )
 9673    }
 9674
 9675    fn go_to_next_hunk_in_direction(
 9676        &mut self,
 9677        snapshot: &DisplaySnapshot,
 9678        initial_point: Point,
 9679        is_wrapped: bool,
 9680        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
 9681        cx: &mut ViewContext<Editor>,
 9682    ) -> Option<MultiBufferDiffHunk> {
 9683        let display_point = initial_point.to_display_point(snapshot);
 9684        let mut hunks = hunks
 9685            .map(|hunk| (diff_hunk_to_display(&hunk, snapshot), hunk))
 9686            .filter(|(display_hunk, _)| {
 9687                is_wrapped || !display_hunk.contains_display_row(display_point.row())
 9688            })
 9689            .dedup();
 9690
 9691        if let Some((display_hunk, hunk)) = hunks.next() {
 9692            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9693                let row = display_hunk.start_display_row();
 9694                let point = DisplayPoint::new(row, 0);
 9695                s.select_display_ranges([point..point]);
 9696            });
 9697
 9698            Some(hunk)
 9699        } else {
 9700            None
 9701        }
 9702    }
 9703
 9704    pub fn go_to_definition(
 9705        &mut self,
 9706        _: &GoToDefinition,
 9707        cx: &mut ViewContext<Self>,
 9708    ) -> Task<Result<Navigated>> {
 9709        let definition = self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
 9710        cx.spawn(|editor, mut cx| async move {
 9711            if definition.await? == Navigated::Yes {
 9712                return Ok(Navigated::Yes);
 9713            }
 9714            match editor.update(&mut cx, |editor, cx| {
 9715                editor.find_all_references(&FindAllReferences, cx)
 9716            })? {
 9717                Some(references) => references.await,
 9718                None => Ok(Navigated::No),
 9719            }
 9720        })
 9721    }
 9722
 9723    pub fn go_to_declaration(
 9724        &mut self,
 9725        _: &GoToDeclaration,
 9726        cx: &mut ViewContext<Self>,
 9727    ) -> Task<Result<Navigated>> {
 9728        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, cx)
 9729    }
 9730
 9731    pub fn go_to_declaration_split(
 9732        &mut self,
 9733        _: &GoToDeclaration,
 9734        cx: &mut ViewContext<Self>,
 9735    ) -> Task<Result<Navigated>> {
 9736        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, cx)
 9737    }
 9738
 9739    pub fn go_to_implementation(
 9740        &mut self,
 9741        _: &GoToImplementation,
 9742        cx: &mut ViewContext<Self>,
 9743    ) -> Task<Result<Navigated>> {
 9744        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx)
 9745    }
 9746
 9747    pub fn go_to_implementation_split(
 9748        &mut self,
 9749        _: &GoToImplementationSplit,
 9750        cx: &mut ViewContext<Self>,
 9751    ) -> Task<Result<Navigated>> {
 9752        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx)
 9753    }
 9754
 9755    pub fn go_to_type_definition(
 9756        &mut self,
 9757        _: &GoToTypeDefinition,
 9758        cx: &mut ViewContext<Self>,
 9759    ) -> Task<Result<Navigated>> {
 9760        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx)
 9761    }
 9762
 9763    pub fn go_to_definition_split(
 9764        &mut self,
 9765        _: &GoToDefinitionSplit,
 9766        cx: &mut ViewContext<Self>,
 9767    ) -> Task<Result<Navigated>> {
 9768        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx)
 9769    }
 9770
 9771    pub fn go_to_type_definition_split(
 9772        &mut self,
 9773        _: &GoToTypeDefinitionSplit,
 9774        cx: &mut ViewContext<Self>,
 9775    ) -> Task<Result<Navigated>> {
 9776        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx)
 9777    }
 9778
 9779    fn go_to_definition_of_kind(
 9780        &mut self,
 9781        kind: GotoDefinitionKind,
 9782        split: bool,
 9783        cx: &mut ViewContext<Self>,
 9784    ) -> Task<Result<Navigated>> {
 9785        let Some(provider) = self.semantics_provider.clone() else {
 9786            return Task::ready(Ok(Navigated::No));
 9787        };
 9788        let head = self.selections.newest::<usize>(cx).head();
 9789        let buffer = self.buffer.read(cx);
 9790        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 9791            text_anchor
 9792        } else {
 9793            return Task::ready(Ok(Navigated::No));
 9794        };
 9795
 9796        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
 9797            return Task::ready(Ok(Navigated::No));
 9798        };
 9799
 9800        cx.spawn(|editor, mut cx| async move {
 9801            let definitions = definitions.await?;
 9802            let navigated = editor
 9803                .update(&mut cx, |editor, cx| {
 9804                    editor.navigate_to_hover_links(
 9805                        Some(kind),
 9806                        definitions
 9807                            .into_iter()
 9808                            .filter(|location| {
 9809                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
 9810                            })
 9811                            .map(HoverLink::Text)
 9812                            .collect::<Vec<_>>(),
 9813                        split,
 9814                        cx,
 9815                    )
 9816                })?
 9817                .await?;
 9818            anyhow::Ok(navigated)
 9819        })
 9820    }
 9821
 9822    pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext<Self>) {
 9823        let position = self.selections.newest_anchor().head();
 9824        let Some((buffer, buffer_position)) =
 9825            self.buffer.read(cx).text_anchor_for_position(position, cx)
 9826        else {
 9827            return;
 9828        };
 9829
 9830        cx.spawn(|editor, mut cx| async move {
 9831            if let Some((_, url)) = find_url(&buffer, buffer_position, cx.clone()) {
 9832                editor.update(&mut cx, |_, cx| {
 9833                    cx.open_url(&url);
 9834                })
 9835            } else {
 9836                Ok(())
 9837            }
 9838        })
 9839        .detach();
 9840    }
 9841
 9842    pub fn open_file(&mut self, _: &OpenFile, cx: &mut ViewContext<Self>) {
 9843        let Some(workspace) = self.workspace() else {
 9844            return;
 9845        };
 9846
 9847        let position = self.selections.newest_anchor().head();
 9848
 9849        let Some((buffer, buffer_position)) =
 9850            self.buffer.read(cx).text_anchor_for_position(position, cx)
 9851        else {
 9852            return;
 9853        };
 9854
 9855        let project = self.project.clone();
 9856
 9857        cx.spawn(|_, mut cx| async move {
 9858            let result = find_file(&buffer, project, buffer_position, &mut cx).await;
 9859
 9860            if let Some((_, path)) = result {
 9861                workspace
 9862                    .update(&mut cx, |workspace, cx| {
 9863                        workspace.open_resolved_path(path, cx)
 9864                    })?
 9865                    .await?;
 9866            }
 9867            anyhow::Ok(())
 9868        })
 9869        .detach();
 9870    }
 9871
 9872    pub(crate) fn navigate_to_hover_links(
 9873        &mut self,
 9874        kind: Option<GotoDefinitionKind>,
 9875        mut definitions: Vec<HoverLink>,
 9876        split: bool,
 9877        cx: &mut ViewContext<Editor>,
 9878    ) -> Task<Result<Navigated>> {
 9879        // If there is one definition, just open it directly
 9880        if definitions.len() == 1 {
 9881            let definition = definitions.pop().unwrap();
 9882
 9883            enum TargetTaskResult {
 9884                Location(Option<Location>),
 9885                AlreadyNavigated,
 9886            }
 9887
 9888            let target_task = match definition {
 9889                HoverLink::Text(link) => {
 9890                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
 9891                }
 9892                HoverLink::InlayHint(lsp_location, server_id) => {
 9893                    let computation = self.compute_target_location(lsp_location, server_id, cx);
 9894                    cx.background_executor().spawn(async move {
 9895                        let location = computation.await?;
 9896                        Ok(TargetTaskResult::Location(location))
 9897                    })
 9898                }
 9899                HoverLink::Url(url) => {
 9900                    cx.open_url(&url);
 9901                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
 9902                }
 9903                HoverLink::File(path) => {
 9904                    if let Some(workspace) = self.workspace() {
 9905                        cx.spawn(|_, mut cx| async move {
 9906                            workspace
 9907                                .update(&mut cx, |workspace, cx| {
 9908                                    workspace.open_resolved_path(path, cx)
 9909                                })?
 9910                                .await
 9911                                .map(|_| TargetTaskResult::AlreadyNavigated)
 9912                        })
 9913                    } else {
 9914                        Task::ready(Ok(TargetTaskResult::Location(None)))
 9915                    }
 9916                }
 9917            };
 9918            cx.spawn(|editor, mut cx| async move {
 9919                let target = match target_task.await.context("target resolution task")? {
 9920                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
 9921                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
 9922                    TargetTaskResult::Location(Some(target)) => target,
 9923                };
 9924
 9925                editor.update(&mut cx, |editor, cx| {
 9926                    let Some(workspace) = editor.workspace() else {
 9927                        return Navigated::No;
 9928                    };
 9929                    let pane = workspace.read(cx).active_pane().clone();
 9930
 9931                    let range = target.range.to_offset(target.buffer.read(cx));
 9932                    let range = editor.range_for_match(&range);
 9933
 9934                    if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
 9935                        let buffer = target.buffer.read(cx);
 9936                        let range = check_multiline_range(buffer, range);
 9937                        editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9938                            s.select_ranges([range]);
 9939                        });
 9940                    } else {
 9941                        cx.window_context().defer(move |cx| {
 9942                            let target_editor: View<Self> =
 9943                                workspace.update(cx, |workspace, cx| {
 9944                                    let pane = if split {
 9945                                        workspace.adjacent_pane(cx)
 9946                                    } else {
 9947                                        workspace.active_pane().clone()
 9948                                    };
 9949
 9950                                    workspace.open_project_item(
 9951                                        pane,
 9952                                        target.buffer.clone(),
 9953                                        true,
 9954                                        true,
 9955                                        cx,
 9956                                    )
 9957                                });
 9958                            target_editor.update(cx, |target_editor, cx| {
 9959                                // When selecting a definition in a different buffer, disable the nav history
 9960                                // to avoid creating a history entry at the previous cursor location.
 9961                                pane.update(cx, |pane, _| pane.disable_history());
 9962                                let buffer = target.buffer.read(cx);
 9963                                let range = check_multiline_range(buffer, range);
 9964                                target_editor.change_selections(
 9965                                    Some(Autoscroll::focused()),
 9966                                    cx,
 9967                                    |s| {
 9968                                        s.select_ranges([range]);
 9969                                    },
 9970                                );
 9971                                pane.update(cx, |pane, _| pane.enable_history());
 9972                            });
 9973                        });
 9974                    }
 9975                    Navigated::Yes
 9976                })
 9977            })
 9978        } else if !definitions.is_empty() {
 9979            cx.spawn(|editor, mut cx| async move {
 9980                let (title, location_tasks, workspace) = editor
 9981                    .update(&mut cx, |editor, cx| {
 9982                        let tab_kind = match kind {
 9983                            Some(GotoDefinitionKind::Implementation) => "Implementations",
 9984                            _ => "Definitions",
 9985                        };
 9986                        let title = definitions
 9987                            .iter()
 9988                            .find_map(|definition| match definition {
 9989                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
 9990                                    let buffer = origin.buffer.read(cx);
 9991                                    format!(
 9992                                        "{} for {}",
 9993                                        tab_kind,
 9994                                        buffer
 9995                                            .text_for_range(origin.range.clone())
 9996                                            .collect::<String>()
 9997                                    )
 9998                                }),
 9999                                HoverLink::InlayHint(_, _) => None,
10000                                HoverLink::Url(_) => None,
10001                                HoverLink::File(_) => None,
10002                            })
10003                            .unwrap_or(tab_kind.to_string());
10004                        let location_tasks = definitions
10005                            .into_iter()
10006                            .map(|definition| match definition {
10007                                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
10008                                HoverLink::InlayHint(lsp_location, server_id) => {
10009                                    editor.compute_target_location(lsp_location, server_id, cx)
10010                                }
10011                                HoverLink::Url(_) => Task::ready(Ok(None)),
10012                                HoverLink::File(_) => Task::ready(Ok(None)),
10013                            })
10014                            .collect::<Vec<_>>();
10015                        (title, location_tasks, editor.workspace().clone())
10016                    })
10017                    .context("location tasks preparation")?;
10018
10019                let locations = future::join_all(location_tasks)
10020                    .await
10021                    .into_iter()
10022                    .filter_map(|location| location.transpose())
10023                    .collect::<Result<_>>()
10024                    .context("location tasks")?;
10025
10026                let Some(workspace) = workspace else {
10027                    return Ok(Navigated::No);
10028                };
10029                let opened = workspace
10030                    .update(&mut cx, |workspace, cx| {
10031                        Self::open_locations_in_multibuffer(workspace, locations, title, split, cx)
10032                    })
10033                    .ok();
10034
10035                anyhow::Ok(Navigated::from_bool(opened.is_some()))
10036            })
10037        } else {
10038            Task::ready(Ok(Navigated::No))
10039        }
10040    }
10041
10042    fn compute_target_location(
10043        &self,
10044        lsp_location: lsp::Location,
10045        server_id: LanguageServerId,
10046        cx: &mut ViewContext<Self>,
10047    ) -> Task<anyhow::Result<Option<Location>>> {
10048        let Some(project) = self.project.clone() else {
10049            return Task::Ready(Some(Ok(None)));
10050        };
10051
10052        cx.spawn(move |editor, mut cx| async move {
10053            let location_task = editor.update(&mut cx, |_, cx| {
10054                project.update(cx, |project, cx| {
10055                    let language_server_name = project
10056                        .language_server_statuses(cx)
10057                        .find(|(id, _)| server_id == *id)
10058                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
10059                    language_server_name.map(|language_server_name| {
10060                        project.open_local_buffer_via_lsp(
10061                            lsp_location.uri.clone(),
10062                            server_id,
10063                            language_server_name,
10064                            cx,
10065                        )
10066                    })
10067                })
10068            })?;
10069            let location = match location_task {
10070                Some(task) => Some({
10071                    let target_buffer_handle = task.await.context("open local buffer")?;
10072                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
10073                        let target_start = target_buffer
10074                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
10075                        let target_end = target_buffer
10076                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
10077                        target_buffer.anchor_after(target_start)
10078                            ..target_buffer.anchor_before(target_end)
10079                    })?;
10080                    Location {
10081                        buffer: target_buffer_handle,
10082                        range,
10083                    }
10084                }),
10085                None => None,
10086            };
10087            Ok(location)
10088        })
10089    }
10090
10091    pub fn find_all_references(
10092        &mut self,
10093        _: &FindAllReferences,
10094        cx: &mut ViewContext<Self>,
10095    ) -> Option<Task<Result<Navigated>>> {
10096        let selection = self.selections.newest::<usize>(cx);
10097        let multi_buffer = self.buffer.read(cx);
10098        let head = selection.head();
10099
10100        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
10101        let head_anchor = multi_buffer_snapshot.anchor_at(
10102            head,
10103            if head < selection.tail() {
10104                Bias::Right
10105            } else {
10106                Bias::Left
10107            },
10108        );
10109
10110        match self
10111            .find_all_references_task_sources
10112            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
10113        {
10114            Ok(_) => {
10115                log::info!(
10116                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
10117                );
10118                return None;
10119            }
10120            Err(i) => {
10121                self.find_all_references_task_sources.insert(i, head_anchor);
10122            }
10123        }
10124
10125        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
10126        let workspace = self.workspace()?;
10127        let project = workspace.read(cx).project().clone();
10128        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
10129        Some(cx.spawn(|editor, mut cx| async move {
10130            let _cleanup = defer({
10131                let mut cx = cx.clone();
10132                move || {
10133                    let _ = editor.update(&mut cx, |editor, _| {
10134                        if let Ok(i) =
10135                            editor
10136                                .find_all_references_task_sources
10137                                .binary_search_by(|anchor| {
10138                                    anchor.cmp(&head_anchor, &multi_buffer_snapshot)
10139                                })
10140                        {
10141                            editor.find_all_references_task_sources.remove(i);
10142                        }
10143                    });
10144                }
10145            });
10146
10147            let locations = references.await?;
10148            if locations.is_empty() {
10149                return anyhow::Ok(Navigated::No);
10150            }
10151
10152            workspace.update(&mut cx, |workspace, cx| {
10153                let title = locations
10154                    .first()
10155                    .as_ref()
10156                    .map(|location| {
10157                        let buffer = location.buffer.read(cx);
10158                        format!(
10159                            "References to `{}`",
10160                            buffer
10161                                .text_for_range(location.range.clone())
10162                                .collect::<String>()
10163                        )
10164                    })
10165                    .unwrap();
10166                Self::open_locations_in_multibuffer(workspace, locations, title, false, cx);
10167                Navigated::Yes
10168            })
10169        }))
10170    }
10171
10172    /// Opens a multibuffer with the given project locations in it
10173    pub fn open_locations_in_multibuffer(
10174        workspace: &mut Workspace,
10175        mut locations: Vec<Location>,
10176        title: String,
10177        split: bool,
10178        cx: &mut ViewContext<Workspace>,
10179    ) {
10180        // If there are multiple definitions, open them in a multibuffer
10181        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
10182        let mut locations = locations.into_iter().peekable();
10183        let mut ranges_to_highlight = Vec::new();
10184        let capability = workspace.project().read(cx).capability();
10185
10186        let excerpt_buffer = cx.new_model(|cx| {
10187            let mut multibuffer = MultiBuffer::new(capability);
10188            while let Some(location) = locations.next() {
10189                let buffer = location.buffer.read(cx);
10190                let mut ranges_for_buffer = Vec::new();
10191                let range = location.range.to_offset(buffer);
10192                ranges_for_buffer.push(range.clone());
10193
10194                while let Some(next_location) = locations.peek() {
10195                    if next_location.buffer == location.buffer {
10196                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
10197                        locations.next();
10198                    } else {
10199                        break;
10200                    }
10201                }
10202
10203                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
10204                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
10205                    location.buffer.clone(),
10206                    ranges_for_buffer,
10207                    DEFAULT_MULTIBUFFER_CONTEXT,
10208                    cx,
10209                ))
10210            }
10211
10212            multibuffer.with_title(title)
10213        });
10214
10215        let editor = cx.new_view(|cx| {
10216            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), true, cx)
10217        });
10218        editor.update(cx, |editor, cx| {
10219            if let Some(first_range) = ranges_to_highlight.first() {
10220                editor.change_selections(None, cx, |selections| {
10221                    selections.clear_disjoint();
10222                    selections.select_anchor_ranges(std::iter::once(first_range.clone()));
10223                });
10224            }
10225            editor.highlight_background::<Self>(
10226                &ranges_to_highlight,
10227                |theme| theme.editor_highlighted_line_background,
10228                cx,
10229            );
10230        });
10231
10232        let item = Box::new(editor);
10233        let item_id = item.item_id();
10234
10235        if split {
10236            workspace.split_item(SplitDirection::Right, item.clone(), cx);
10237        } else {
10238            let destination_index = workspace.active_pane().update(cx, |pane, cx| {
10239                if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
10240                    pane.close_current_preview_item(cx)
10241                } else {
10242                    None
10243                }
10244            });
10245            workspace.add_item_to_active_pane(item.clone(), destination_index, true, cx);
10246        }
10247        workspace.active_pane().update(cx, |pane, cx| {
10248            pane.set_preview_item_id(Some(item_id), cx);
10249        });
10250    }
10251
10252    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
10253        use language::ToOffset as _;
10254
10255        let provider = self.semantics_provider.clone()?;
10256        let selection = self.selections.newest_anchor().clone();
10257        let (cursor_buffer, cursor_buffer_position) = self
10258            .buffer
10259            .read(cx)
10260            .text_anchor_for_position(selection.head(), cx)?;
10261        let (tail_buffer, cursor_buffer_position_end) = self
10262            .buffer
10263            .read(cx)
10264            .text_anchor_for_position(selection.tail(), cx)?;
10265        if tail_buffer != cursor_buffer {
10266            return None;
10267        }
10268
10269        let snapshot = cursor_buffer.read(cx).snapshot();
10270        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
10271        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
10272        let prepare_rename = provider
10273            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
10274            .unwrap_or_else(|| Task::ready(Ok(None)));
10275        drop(snapshot);
10276
10277        Some(cx.spawn(|this, mut cx| async move {
10278            let rename_range = if let Some(range) = prepare_rename.await? {
10279                Some(range)
10280            } else {
10281                this.update(&mut cx, |this, cx| {
10282                    let buffer = this.buffer.read(cx).snapshot(cx);
10283                    let mut buffer_highlights = this
10284                        .document_highlights_for_position(selection.head(), &buffer)
10285                        .filter(|highlight| {
10286                            highlight.start.excerpt_id == selection.head().excerpt_id
10287                                && highlight.end.excerpt_id == selection.head().excerpt_id
10288                        });
10289                    buffer_highlights
10290                        .next()
10291                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
10292                })?
10293            };
10294            if let Some(rename_range) = rename_range {
10295                this.update(&mut cx, |this, cx| {
10296                    let snapshot = cursor_buffer.read(cx).snapshot();
10297                    let rename_buffer_range = rename_range.to_offset(&snapshot);
10298                    let cursor_offset_in_rename_range =
10299                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
10300                    let cursor_offset_in_rename_range_end =
10301                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
10302
10303                    this.take_rename(false, cx);
10304                    let buffer = this.buffer.read(cx).read(cx);
10305                    let cursor_offset = selection.head().to_offset(&buffer);
10306                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
10307                    let rename_end = rename_start + rename_buffer_range.len();
10308                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
10309                    let mut old_highlight_id = None;
10310                    let old_name: Arc<str> = buffer
10311                        .chunks(rename_start..rename_end, true)
10312                        .map(|chunk| {
10313                            if old_highlight_id.is_none() {
10314                                old_highlight_id = chunk.syntax_highlight_id;
10315                            }
10316                            chunk.text
10317                        })
10318                        .collect::<String>()
10319                        .into();
10320
10321                    drop(buffer);
10322
10323                    // Position the selection in the rename editor so that it matches the current selection.
10324                    this.show_local_selections = false;
10325                    let rename_editor = cx.new_view(|cx| {
10326                        let mut editor = Editor::single_line(cx);
10327                        editor.buffer.update(cx, |buffer, cx| {
10328                            buffer.edit([(0..0, old_name.clone())], None, cx)
10329                        });
10330                        let rename_selection_range = match cursor_offset_in_rename_range
10331                            .cmp(&cursor_offset_in_rename_range_end)
10332                        {
10333                            Ordering::Equal => {
10334                                editor.select_all(&SelectAll, cx);
10335                                return editor;
10336                            }
10337                            Ordering::Less => {
10338                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
10339                            }
10340                            Ordering::Greater => {
10341                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
10342                            }
10343                        };
10344                        if rename_selection_range.end > old_name.len() {
10345                            editor.select_all(&SelectAll, cx);
10346                        } else {
10347                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
10348                                s.select_ranges([rename_selection_range]);
10349                            });
10350                        }
10351                        editor
10352                    });
10353                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
10354                        if e == &EditorEvent::Focused {
10355                            cx.emit(EditorEvent::FocusedIn)
10356                        }
10357                    })
10358                    .detach();
10359
10360                    let write_highlights =
10361                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
10362                    let read_highlights =
10363                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
10364                    let ranges = write_highlights
10365                        .iter()
10366                        .flat_map(|(_, ranges)| ranges.iter())
10367                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
10368                        .cloned()
10369                        .collect();
10370
10371                    this.highlight_text::<Rename>(
10372                        ranges,
10373                        HighlightStyle {
10374                            fade_out: Some(0.6),
10375                            ..Default::default()
10376                        },
10377                        cx,
10378                    );
10379                    let rename_focus_handle = rename_editor.focus_handle(cx);
10380                    cx.focus(&rename_focus_handle);
10381                    let block_id = this.insert_blocks(
10382                        [BlockProperties {
10383                            style: BlockStyle::Flex,
10384                            placement: BlockPlacement::Below(range.start),
10385                            height: 1,
10386                            render: Box::new({
10387                                let rename_editor = rename_editor.clone();
10388                                move |cx: &mut BlockContext| {
10389                                    let mut text_style = cx.editor_style.text.clone();
10390                                    if let Some(highlight_style) = old_highlight_id
10391                                        .and_then(|h| h.style(&cx.editor_style.syntax))
10392                                    {
10393                                        text_style = text_style.highlight(highlight_style);
10394                                    }
10395                                    div()
10396                                        .pl(cx.anchor_x)
10397                                        .child(EditorElement::new(
10398                                            &rename_editor,
10399                                            EditorStyle {
10400                                                background: cx.theme().system().transparent,
10401                                                local_player: cx.editor_style.local_player,
10402                                                text: text_style,
10403                                                scrollbar_width: cx.editor_style.scrollbar_width,
10404                                                syntax: cx.editor_style.syntax.clone(),
10405                                                status: cx.editor_style.status.clone(),
10406                                                inlay_hints_style: HighlightStyle {
10407                                                    font_weight: Some(FontWeight::BOLD),
10408                                                    ..make_inlay_hints_style(cx)
10409                                                },
10410                                                suggestions_style: HighlightStyle {
10411                                                    color: Some(cx.theme().status().predictive),
10412                                                    ..HighlightStyle::default()
10413                                                },
10414                                                ..EditorStyle::default()
10415                                            },
10416                                        ))
10417                                        .into_any_element()
10418                                }
10419                            }),
10420                            priority: 0,
10421                        }],
10422                        Some(Autoscroll::fit()),
10423                        cx,
10424                    )[0];
10425                    this.pending_rename = Some(RenameState {
10426                        range,
10427                        old_name,
10428                        editor: rename_editor,
10429                        block_id,
10430                    });
10431                })?;
10432            }
10433
10434            Ok(())
10435        }))
10436    }
10437
10438    pub fn confirm_rename(
10439        &mut self,
10440        _: &ConfirmRename,
10441        cx: &mut ViewContext<Self>,
10442    ) -> Option<Task<Result<()>>> {
10443        let rename = self.take_rename(false, cx)?;
10444        let workspace = self.workspace()?.downgrade();
10445        let (buffer, start) = self
10446            .buffer
10447            .read(cx)
10448            .text_anchor_for_position(rename.range.start, cx)?;
10449        let (end_buffer, _) = self
10450            .buffer
10451            .read(cx)
10452            .text_anchor_for_position(rename.range.end, cx)?;
10453        if buffer != end_buffer {
10454            return None;
10455        }
10456
10457        let old_name = rename.old_name;
10458        let new_name = rename.editor.read(cx).text(cx);
10459
10460        let rename = self.semantics_provider.as_ref()?.perform_rename(
10461            &buffer,
10462            start,
10463            new_name.clone(),
10464            cx,
10465        )?;
10466
10467        Some(cx.spawn(|editor, mut cx| async move {
10468            let project_transaction = rename.await?;
10469            Self::open_project_transaction(
10470                &editor,
10471                workspace,
10472                project_transaction,
10473                format!("Rename: {}{}", old_name, new_name),
10474                cx.clone(),
10475            )
10476            .await?;
10477
10478            editor.update(&mut cx, |editor, cx| {
10479                editor.refresh_document_highlights(cx);
10480            })?;
10481            Ok(())
10482        }))
10483    }
10484
10485    fn take_rename(
10486        &mut self,
10487        moving_cursor: bool,
10488        cx: &mut ViewContext<Self>,
10489    ) -> Option<RenameState> {
10490        let rename = self.pending_rename.take()?;
10491        if rename.editor.focus_handle(cx).is_focused(cx) {
10492            cx.focus(&self.focus_handle);
10493        }
10494
10495        self.remove_blocks(
10496            [rename.block_id].into_iter().collect(),
10497            Some(Autoscroll::fit()),
10498            cx,
10499        );
10500        self.clear_highlights::<Rename>(cx);
10501        self.show_local_selections = true;
10502
10503        if moving_cursor {
10504            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
10505                editor.selections.newest::<usize>(cx).head()
10506            });
10507
10508            // Update the selection to match the position of the selection inside
10509            // the rename editor.
10510            let snapshot = self.buffer.read(cx).read(cx);
10511            let rename_range = rename.range.to_offset(&snapshot);
10512            let cursor_in_editor = snapshot
10513                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
10514                .min(rename_range.end);
10515            drop(snapshot);
10516
10517            self.change_selections(None, cx, |s| {
10518                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
10519            });
10520        } else {
10521            self.refresh_document_highlights(cx);
10522        }
10523
10524        Some(rename)
10525    }
10526
10527    pub fn pending_rename(&self) -> Option<&RenameState> {
10528        self.pending_rename.as_ref()
10529    }
10530
10531    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
10532        let project = match &self.project {
10533            Some(project) => project.clone(),
10534            None => return None,
10535        };
10536
10537        Some(self.perform_format(project, FormatTrigger::Manual, FormatTarget::Buffer, cx))
10538    }
10539
10540    fn format_selections(
10541        &mut self,
10542        _: &FormatSelections,
10543        cx: &mut ViewContext<Self>,
10544    ) -> Option<Task<Result<()>>> {
10545        let project = match &self.project {
10546            Some(project) => project.clone(),
10547            None => return None,
10548        };
10549
10550        let selections = self
10551            .selections
10552            .all_adjusted(cx)
10553            .into_iter()
10554            .filter(|s| !s.is_empty())
10555            .collect_vec();
10556
10557        Some(self.perform_format(
10558            project,
10559            FormatTrigger::Manual,
10560            FormatTarget::Ranges(selections),
10561            cx,
10562        ))
10563    }
10564
10565    fn perform_format(
10566        &mut self,
10567        project: Model<Project>,
10568        trigger: FormatTrigger,
10569        target: FormatTarget,
10570        cx: &mut ViewContext<Self>,
10571    ) -> Task<Result<()>> {
10572        let buffer = self.buffer().clone();
10573        let mut buffers = buffer.read(cx).all_buffers();
10574        if trigger == FormatTrigger::Save {
10575            buffers.retain(|buffer| buffer.read(cx).is_dirty());
10576        }
10577
10578        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
10579        let format = project.update(cx, |project, cx| {
10580            project.format(buffers, true, trigger, target, cx)
10581        });
10582
10583        cx.spawn(|_, mut cx| async move {
10584            let transaction = futures::select_biased! {
10585                () = timeout => {
10586                    log::warn!("timed out waiting for formatting");
10587                    None
10588                }
10589                transaction = format.log_err().fuse() => transaction,
10590            };
10591
10592            buffer
10593                .update(&mut cx, |buffer, cx| {
10594                    if let Some(transaction) = transaction {
10595                        if !buffer.is_singleton() {
10596                            buffer.push_transaction(&transaction.0, cx);
10597                        }
10598                    }
10599
10600                    cx.notify();
10601                })
10602                .ok();
10603
10604            Ok(())
10605        })
10606    }
10607
10608    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
10609        if let Some(project) = self.project.clone() {
10610            self.buffer.update(cx, |multi_buffer, cx| {
10611                project.update(cx, |project, cx| {
10612                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
10613                });
10614            })
10615        }
10616    }
10617
10618    fn cancel_language_server_work(
10619        &mut self,
10620        _: &actions::CancelLanguageServerWork,
10621        cx: &mut ViewContext<Self>,
10622    ) {
10623        if let Some(project) = self.project.clone() {
10624            self.buffer.update(cx, |multi_buffer, cx| {
10625                project.update(cx, |project, cx| {
10626                    project.cancel_language_server_work_for_buffers(multi_buffer.all_buffers(), cx);
10627                });
10628            })
10629        }
10630    }
10631
10632    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
10633        cx.show_character_palette();
10634    }
10635
10636    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
10637        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
10638            let buffer = self.buffer.read(cx).snapshot(cx);
10639            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
10640            let is_valid = buffer
10641                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
10642                .any(|entry| {
10643                    entry.diagnostic.is_primary
10644                        && !entry.range.is_empty()
10645                        && entry.range.start == primary_range_start
10646                        && entry.diagnostic.message == active_diagnostics.primary_message
10647                });
10648
10649            if is_valid != active_diagnostics.is_valid {
10650                active_diagnostics.is_valid = is_valid;
10651                let mut new_styles = HashMap::default();
10652                for (block_id, diagnostic) in &active_diagnostics.blocks {
10653                    new_styles.insert(
10654                        *block_id,
10655                        diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
10656                    );
10657                }
10658                self.display_map.update(cx, |display_map, _cx| {
10659                    display_map.replace_blocks(new_styles)
10660                });
10661            }
10662        }
10663    }
10664
10665    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
10666        self.dismiss_diagnostics(cx);
10667        let snapshot = self.snapshot(cx);
10668        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
10669            let buffer = self.buffer.read(cx).snapshot(cx);
10670
10671            let mut primary_range = None;
10672            let mut primary_message = None;
10673            let mut group_end = Point::zero();
10674            let diagnostic_group = buffer
10675                .diagnostic_group::<MultiBufferPoint>(group_id)
10676                .filter_map(|entry| {
10677                    if snapshot.is_line_folded(MultiBufferRow(entry.range.start.row))
10678                        && (entry.range.start.row == entry.range.end.row
10679                            || snapshot.is_line_folded(MultiBufferRow(entry.range.end.row)))
10680                    {
10681                        return None;
10682                    }
10683                    if entry.range.end > group_end {
10684                        group_end = entry.range.end;
10685                    }
10686                    if entry.diagnostic.is_primary {
10687                        primary_range = Some(entry.range.clone());
10688                        primary_message = Some(entry.diagnostic.message.clone());
10689                    }
10690                    Some(entry)
10691                })
10692                .collect::<Vec<_>>();
10693            let primary_range = primary_range?;
10694            let primary_message = primary_message?;
10695            let primary_range =
10696                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
10697
10698            let blocks = display_map
10699                .insert_blocks(
10700                    diagnostic_group.iter().map(|entry| {
10701                        let diagnostic = entry.diagnostic.clone();
10702                        let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
10703                        BlockProperties {
10704                            style: BlockStyle::Fixed,
10705                            placement: BlockPlacement::Below(
10706                                buffer.anchor_after(entry.range.start),
10707                            ),
10708                            height: message_height,
10709                            render: diagnostic_block_renderer(diagnostic, None, true, true),
10710                            priority: 0,
10711                        }
10712                    }),
10713                    cx,
10714                )
10715                .into_iter()
10716                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
10717                .collect();
10718
10719            Some(ActiveDiagnosticGroup {
10720                primary_range,
10721                primary_message,
10722                group_id,
10723                blocks,
10724                is_valid: true,
10725            })
10726        });
10727        self.active_diagnostics.is_some()
10728    }
10729
10730    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
10731        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
10732            self.display_map.update(cx, |display_map, cx| {
10733                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
10734            });
10735            cx.notify();
10736        }
10737    }
10738
10739    pub fn set_selections_from_remote(
10740        &mut self,
10741        selections: Vec<Selection<Anchor>>,
10742        pending_selection: Option<Selection<Anchor>>,
10743        cx: &mut ViewContext<Self>,
10744    ) {
10745        let old_cursor_position = self.selections.newest_anchor().head();
10746        self.selections.change_with(cx, |s| {
10747            s.select_anchors(selections);
10748            if let Some(pending_selection) = pending_selection {
10749                s.set_pending(pending_selection, SelectMode::Character);
10750            } else {
10751                s.clear_pending();
10752            }
10753        });
10754        self.selections_did_change(false, &old_cursor_position, true, cx);
10755    }
10756
10757    fn push_to_selection_history(&mut self) {
10758        self.selection_history.push(SelectionHistoryEntry {
10759            selections: self.selections.disjoint_anchors(),
10760            select_next_state: self.select_next_state.clone(),
10761            select_prev_state: self.select_prev_state.clone(),
10762            add_selections_state: self.add_selections_state.clone(),
10763        });
10764    }
10765
10766    pub fn transact(
10767        &mut self,
10768        cx: &mut ViewContext<Self>,
10769        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
10770    ) -> Option<TransactionId> {
10771        self.start_transaction_at(Instant::now(), cx);
10772        update(self, cx);
10773        self.end_transaction_at(Instant::now(), cx)
10774    }
10775
10776    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
10777        self.end_selection(cx);
10778        if let Some(tx_id) = self
10779            .buffer
10780            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
10781        {
10782            self.selection_history
10783                .insert_transaction(tx_id, self.selections.disjoint_anchors());
10784            cx.emit(EditorEvent::TransactionBegun {
10785                transaction_id: tx_id,
10786            })
10787        }
10788    }
10789
10790    fn end_transaction_at(
10791        &mut self,
10792        now: Instant,
10793        cx: &mut ViewContext<Self>,
10794    ) -> Option<TransactionId> {
10795        if let Some(transaction_id) = self
10796            .buffer
10797            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
10798        {
10799            if let Some((_, end_selections)) =
10800                self.selection_history.transaction_mut(transaction_id)
10801            {
10802                *end_selections = Some(self.selections.disjoint_anchors());
10803            } else {
10804                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
10805            }
10806
10807            cx.emit(EditorEvent::Edited { transaction_id });
10808            Some(transaction_id)
10809        } else {
10810            None
10811        }
10812    }
10813
10814    pub fn toggle_fold(&mut self, _: &actions::ToggleFold, cx: &mut ViewContext<Self>) {
10815        let selection = self.selections.newest::<Point>(cx);
10816
10817        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10818        let range = if selection.is_empty() {
10819            let point = selection.head().to_display_point(&display_map);
10820            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
10821            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
10822                .to_point(&display_map);
10823            start..end
10824        } else {
10825            selection.range()
10826        };
10827        if display_map.folds_in_range(range).next().is_some() {
10828            self.unfold_lines(&Default::default(), cx)
10829        } else {
10830            self.fold(&Default::default(), cx)
10831        }
10832    }
10833
10834    pub fn toggle_fold_recursive(
10835        &mut self,
10836        _: &actions::ToggleFoldRecursive,
10837        cx: &mut ViewContext<Self>,
10838    ) {
10839        let selection = self.selections.newest::<Point>(cx);
10840
10841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10842        let range = if selection.is_empty() {
10843            let point = selection.head().to_display_point(&display_map);
10844            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
10845            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
10846                .to_point(&display_map);
10847            start..end
10848        } else {
10849            selection.range()
10850        };
10851        if display_map.folds_in_range(range).next().is_some() {
10852            self.unfold_recursive(&Default::default(), cx)
10853        } else {
10854            self.fold_recursive(&Default::default(), cx)
10855        }
10856    }
10857
10858    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
10859        let mut fold_ranges = Vec::new();
10860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10861        let selections = self.selections.all_adjusted(cx);
10862
10863        for selection in selections {
10864            let range = selection.range().sorted();
10865            let buffer_start_row = range.start.row;
10866
10867            if range.start.row != range.end.row {
10868                let mut found = false;
10869                let mut row = range.start.row;
10870                while row <= range.end.row {
10871                    if let Some((foldable_range, fold_text)) =
10872                        { display_map.foldable_range(MultiBufferRow(row)) }
10873                    {
10874                        found = true;
10875                        row = foldable_range.end.row + 1;
10876                        fold_ranges.push((foldable_range, fold_text));
10877                    } else {
10878                        row += 1
10879                    }
10880                }
10881                if found {
10882                    continue;
10883                }
10884            }
10885
10886            for row in (0..=range.start.row).rev() {
10887                if let Some((foldable_range, fold_text)) =
10888                    display_map.foldable_range(MultiBufferRow(row))
10889                {
10890                    if foldable_range.end.row >= buffer_start_row {
10891                        fold_ranges.push((foldable_range, fold_text));
10892                        if row <= range.start.row {
10893                            break;
10894                        }
10895                    }
10896                }
10897            }
10898        }
10899
10900        self.fold_ranges(fold_ranges, true, cx);
10901    }
10902
10903    fn fold_at_level(&mut self, fold_at: &FoldAtLevel, cx: &mut ViewContext<Self>) {
10904        let fold_at_level = fold_at.level;
10905        let snapshot = self.buffer.read(cx).snapshot(cx);
10906        let mut fold_ranges = Vec::new();
10907        let mut stack = vec![(0, snapshot.max_buffer_row().0, 1)];
10908
10909        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
10910            while start_row < end_row {
10911                match self.snapshot(cx).foldable_range(MultiBufferRow(start_row)) {
10912                    Some(foldable_range) => {
10913                        let nested_start_row = foldable_range.0.start.row + 1;
10914                        let nested_end_row = foldable_range.0.end.row;
10915
10916                        if current_level < fold_at_level {
10917                            stack.push((nested_start_row, nested_end_row, current_level + 1));
10918                        } else if current_level == fold_at_level {
10919                            fold_ranges.push(foldable_range);
10920                        }
10921
10922                        start_row = nested_end_row + 1;
10923                    }
10924                    None => start_row += 1,
10925                }
10926            }
10927        }
10928
10929        self.fold_ranges(fold_ranges, true, cx);
10930    }
10931
10932    pub fn fold_all(&mut self, _: &actions::FoldAll, cx: &mut ViewContext<Self>) {
10933        let mut fold_ranges = Vec::new();
10934        let snapshot = self.buffer.read(cx).snapshot(cx);
10935
10936        for row in 0..snapshot.max_buffer_row().0 {
10937            if let Some(foldable_range) = self.snapshot(cx).foldable_range(MultiBufferRow(row)) {
10938                fold_ranges.push(foldable_range);
10939            }
10940        }
10941
10942        self.fold_ranges(fold_ranges, true, cx);
10943    }
10944
10945    pub fn fold_recursive(&mut self, _: &actions::FoldRecursive, cx: &mut ViewContext<Self>) {
10946        let mut fold_ranges = Vec::new();
10947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10948        let selections = self.selections.all_adjusted(cx);
10949
10950        for selection in selections {
10951            let range = selection.range().sorted();
10952            let buffer_start_row = range.start.row;
10953
10954            if range.start.row != range.end.row {
10955                let mut found = false;
10956                for row in range.start.row..=range.end.row {
10957                    if let Some((foldable_range, fold_text)) =
10958                        { display_map.foldable_range(MultiBufferRow(row)) }
10959                    {
10960                        found = true;
10961                        fold_ranges.push((foldable_range, fold_text));
10962                    }
10963                }
10964                if found {
10965                    continue;
10966                }
10967            }
10968
10969            for row in (0..=range.start.row).rev() {
10970                if let Some((foldable_range, fold_text)) =
10971                    display_map.foldable_range(MultiBufferRow(row))
10972                {
10973                    if foldable_range.end.row >= buffer_start_row {
10974                        fold_ranges.push((foldable_range, fold_text));
10975                    } else {
10976                        break;
10977                    }
10978                }
10979            }
10980        }
10981
10982        self.fold_ranges(fold_ranges, true, cx);
10983    }
10984
10985    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
10986        let buffer_row = fold_at.buffer_row;
10987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10988
10989        if let Some((fold_range, placeholder)) = display_map.foldable_range(buffer_row) {
10990            let autoscroll = self
10991                .selections
10992                .all::<Point>(cx)
10993                .iter()
10994                .any(|selection| fold_range.overlaps(&selection.range()));
10995
10996            self.fold_ranges([(fold_range, placeholder)], autoscroll, cx);
10997        }
10998    }
10999
11000    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
11001        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11002        let buffer = &display_map.buffer_snapshot;
11003        let selections = self.selections.all::<Point>(cx);
11004        let ranges = selections
11005            .iter()
11006            .map(|s| {
11007                let range = s.display_range(&display_map).sorted();
11008                let mut start = range.start.to_point(&display_map);
11009                let mut end = range.end.to_point(&display_map);
11010                start.column = 0;
11011                end.column = buffer.line_len(MultiBufferRow(end.row));
11012                start..end
11013            })
11014            .collect::<Vec<_>>();
11015
11016        self.unfold_ranges(&ranges, true, true, cx);
11017    }
11018
11019    pub fn unfold_recursive(&mut self, _: &UnfoldRecursive, cx: &mut ViewContext<Self>) {
11020        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11021        let selections = self.selections.all::<Point>(cx);
11022        let ranges = selections
11023            .iter()
11024            .map(|s| {
11025                let mut range = s.display_range(&display_map).sorted();
11026                *range.start.column_mut() = 0;
11027                *range.end.column_mut() = display_map.line_len(range.end.row());
11028                let start = range.start.to_point(&display_map);
11029                let end = range.end.to_point(&display_map);
11030                start..end
11031            })
11032            .collect::<Vec<_>>();
11033
11034        self.unfold_ranges(&ranges, true, true, cx);
11035    }
11036
11037    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
11038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11039
11040        let intersection_range = Point::new(unfold_at.buffer_row.0, 0)
11041            ..Point::new(
11042                unfold_at.buffer_row.0,
11043                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
11044            );
11045
11046        let autoscroll = self
11047            .selections
11048            .all::<Point>(cx)
11049            .iter()
11050            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
11051
11052        self.unfold_ranges(&[intersection_range], true, autoscroll, cx)
11053    }
11054
11055    pub fn unfold_all(&mut self, _: &actions::UnfoldAll, cx: &mut ViewContext<Self>) {
11056        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11057        self.unfold_ranges(
11058            &[Point::zero()..display_map.max_point().to_point(&display_map)],
11059            true,
11060            true,
11061            cx,
11062        );
11063    }
11064
11065    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
11066        let selections = self.selections.all::<Point>(cx);
11067        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11068        let line_mode = self.selections.line_mode;
11069        let ranges = selections.into_iter().map(|s| {
11070            if line_mode {
11071                let start = Point::new(s.start.row, 0);
11072                let end = Point::new(
11073                    s.end.row,
11074                    display_map
11075                        .buffer_snapshot
11076                        .line_len(MultiBufferRow(s.end.row)),
11077                );
11078                (start..end, display_map.fold_placeholder.clone())
11079            } else {
11080                (s.start..s.end, display_map.fold_placeholder.clone())
11081            }
11082        });
11083        self.fold_ranges(ranges, true, cx);
11084    }
11085
11086    pub fn fold_ranges<T: ToOffset + Clone>(
11087        &mut self,
11088        ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>,
11089        auto_scroll: bool,
11090        cx: &mut ViewContext<Self>,
11091    ) {
11092        let mut fold_ranges = Vec::new();
11093        let mut buffers_affected = HashMap::default();
11094        let multi_buffer = self.buffer().read(cx);
11095        for (fold_range, fold_text) in ranges {
11096            if let Some((_, buffer, _)) =
11097                multi_buffer.excerpt_containing(fold_range.start.clone(), cx)
11098            {
11099                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
11100            };
11101            fold_ranges.push((fold_range, fold_text));
11102        }
11103
11104        let mut ranges = fold_ranges.into_iter().peekable();
11105        if ranges.peek().is_some() {
11106            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
11107
11108            if auto_scroll {
11109                self.request_autoscroll(Autoscroll::fit(), cx);
11110            }
11111
11112            for buffer in buffers_affected.into_values() {
11113                self.sync_expanded_diff_hunks(buffer, cx);
11114            }
11115
11116            cx.notify();
11117
11118            if let Some(active_diagnostics) = self.active_diagnostics.take() {
11119                // Clear diagnostics block when folding a range that contains it.
11120                let snapshot = self.snapshot(cx);
11121                if snapshot.intersects_fold(active_diagnostics.primary_range.start) {
11122                    drop(snapshot);
11123                    self.active_diagnostics = Some(active_diagnostics);
11124                    self.dismiss_diagnostics(cx);
11125                } else {
11126                    self.active_diagnostics = Some(active_diagnostics);
11127                }
11128            }
11129
11130            self.scrollbar_marker_state.dirty = true;
11131        }
11132    }
11133
11134    /// Removes any folds whose ranges intersect any of the given ranges.
11135    pub fn unfold_ranges<T: ToOffset + Clone>(
11136        &mut self,
11137        ranges: &[Range<T>],
11138        inclusive: bool,
11139        auto_scroll: bool,
11140        cx: &mut ViewContext<Self>,
11141    ) {
11142        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
11143            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
11144        });
11145    }
11146
11147    /// Removes any folds with the given ranges.
11148    pub fn remove_folds_with_type<T: ToOffset + Clone>(
11149        &mut self,
11150        ranges: &[Range<T>],
11151        type_id: TypeId,
11152        auto_scroll: bool,
11153        cx: &mut ViewContext<Self>,
11154    ) {
11155        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
11156            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
11157        });
11158    }
11159
11160    fn remove_folds_with<T: ToOffset + Clone>(
11161        &mut self,
11162        ranges: &[Range<T>],
11163        auto_scroll: bool,
11164        cx: &mut ViewContext<Self>,
11165        update: impl FnOnce(&mut DisplayMap, &mut ModelContext<DisplayMap>),
11166    ) {
11167        if ranges.is_empty() {
11168            return;
11169        }
11170
11171        let mut buffers_affected = HashMap::default();
11172        let multi_buffer = self.buffer().read(cx);
11173        for range in ranges {
11174            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
11175                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
11176            };
11177        }
11178
11179        self.display_map.update(cx, update);
11180        if auto_scroll {
11181            self.request_autoscroll(Autoscroll::fit(), cx);
11182        }
11183
11184        for buffer in buffers_affected.into_values() {
11185            self.sync_expanded_diff_hunks(buffer, cx);
11186        }
11187
11188        cx.notify();
11189        self.scrollbar_marker_state.dirty = true;
11190        self.active_indent_guides_state.dirty = true;
11191    }
11192
11193    pub fn default_fold_placeholder(&self, cx: &AppContext) -> FoldPlaceholder {
11194        self.display_map.read(cx).fold_placeholder.clone()
11195    }
11196
11197    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
11198        if hovered != self.gutter_hovered {
11199            self.gutter_hovered = hovered;
11200            cx.notify();
11201        }
11202    }
11203
11204    pub fn insert_blocks(
11205        &mut self,
11206        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
11207        autoscroll: Option<Autoscroll>,
11208        cx: &mut ViewContext<Self>,
11209    ) -> Vec<CustomBlockId> {
11210        let blocks = self
11211            .display_map
11212            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
11213        if let Some(autoscroll) = autoscroll {
11214            self.request_autoscroll(autoscroll, cx);
11215        }
11216        cx.notify();
11217        blocks
11218    }
11219
11220    pub fn resize_blocks(
11221        &mut self,
11222        heights: HashMap<CustomBlockId, u32>,
11223        autoscroll: Option<Autoscroll>,
11224        cx: &mut ViewContext<Self>,
11225    ) {
11226        self.display_map
11227            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
11228        if let Some(autoscroll) = autoscroll {
11229            self.request_autoscroll(autoscroll, cx);
11230        }
11231        cx.notify();
11232    }
11233
11234    pub fn replace_blocks(
11235        &mut self,
11236        renderers: HashMap<CustomBlockId, RenderBlock>,
11237        autoscroll: Option<Autoscroll>,
11238        cx: &mut ViewContext<Self>,
11239    ) {
11240        self.display_map
11241            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
11242        if let Some(autoscroll) = autoscroll {
11243            self.request_autoscroll(autoscroll, cx);
11244        }
11245        cx.notify();
11246    }
11247
11248    pub fn remove_blocks(
11249        &mut self,
11250        block_ids: HashSet<CustomBlockId>,
11251        autoscroll: Option<Autoscroll>,
11252        cx: &mut ViewContext<Self>,
11253    ) {
11254        self.display_map.update(cx, |display_map, cx| {
11255            display_map.remove_blocks(block_ids, cx)
11256        });
11257        if let Some(autoscroll) = autoscroll {
11258            self.request_autoscroll(autoscroll, cx);
11259        }
11260        cx.notify();
11261    }
11262
11263    pub fn row_for_block(
11264        &self,
11265        block_id: CustomBlockId,
11266        cx: &mut ViewContext<Self>,
11267    ) -> Option<DisplayRow> {
11268        self.display_map
11269            .update(cx, |map, cx| map.row_for_block(block_id, cx))
11270    }
11271
11272    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
11273        self.focused_block = Some(focused_block);
11274    }
11275
11276    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
11277        self.focused_block.take()
11278    }
11279
11280    pub fn insert_creases(
11281        &mut self,
11282        creases: impl IntoIterator<Item = Crease>,
11283        cx: &mut ViewContext<Self>,
11284    ) -> Vec<CreaseId> {
11285        self.display_map
11286            .update(cx, |map, cx| map.insert_creases(creases, cx))
11287    }
11288
11289    pub fn remove_creases(
11290        &mut self,
11291        ids: impl IntoIterator<Item = CreaseId>,
11292        cx: &mut ViewContext<Self>,
11293    ) {
11294        self.display_map
11295            .update(cx, |map, cx| map.remove_creases(ids, cx));
11296    }
11297
11298    pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow {
11299        self.display_map
11300            .update(cx, |map, cx| map.snapshot(cx))
11301            .longest_row()
11302    }
11303
11304    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
11305        self.display_map
11306            .update(cx, |map, cx| map.snapshot(cx))
11307            .max_point()
11308    }
11309
11310    pub fn text(&self, cx: &AppContext) -> String {
11311        self.buffer.read(cx).read(cx).text()
11312    }
11313
11314    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
11315        let text = self.text(cx);
11316        let text = text.trim();
11317
11318        if text.is_empty() {
11319            return None;
11320        }
11321
11322        Some(text.to_string())
11323    }
11324
11325    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
11326        self.transact(cx, |this, cx| {
11327            this.buffer
11328                .read(cx)
11329                .as_singleton()
11330                .expect("you can only call set_text on editors for singleton buffers")
11331                .update(cx, |buffer, cx| buffer.set_text(text, cx));
11332        });
11333    }
11334
11335    pub fn display_text(&self, cx: &mut AppContext) -> String {
11336        self.display_map
11337            .update(cx, |map, cx| map.snapshot(cx))
11338            .text()
11339    }
11340
11341    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
11342        let mut wrap_guides = smallvec::smallvec![];
11343
11344        if self.show_wrap_guides == Some(false) {
11345            return wrap_guides;
11346        }
11347
11348        let settings = self.buffer.read(cx).settings_at(0, cx);
11349        if settings.show_wrap_guides {
11350            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
11351                wrap_guides.push((soft_wrap as usize, true));
11352            } else if let SoftWrap::Bounded(soft_wrap) = self.soft_wrap_mode(cx) {
11353                wrap_guides.push((soft_wrap as usize, true));
11354            }
11355            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
11356        }
11357
11358        wrap_guides
11359    }
11360
11361    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
11362        let settings = self.buffer.read(cx).settings_at(0, cx);
11363        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
11364        match mode {
11365            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
11366                SoftWrap::None
11367            }
11368            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
11369            language_settings::SoftWrap::PreferredLineLength => {
11370                SoftWrap::Column(settings.preferred_line_length)
11371            }
11372            language_settings::SoftWrap::Bounded => {
11373                SoftWrap::Bounded(settings.preferred_line_length)
11374            }
11375        }
11376    }
11377
11378    pub fn set_soft_wrap_mode(
11379        &mut self,
11380        mode: language_settings::SoftWrap,
11381        cx: &mut ViewContext<Self>,
11382    ) {
11383        self.soft_wrap_mode_override = Some(mode);
11384        cx.notify();
11385    }
11386
11387    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
11388        self.text_style_refinement = Some(style);
11389    }
11390
11391    /// called by the Element so we know what style we were most recently rendered with.
11392    pub(crate) fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
11393        let rem_size = cx.rem_size();
11394        self.display_map.update(cx, |map, cx| {
11395            map.set_font(
11396                style.text.font(),
11397                style.text.font_size.to_pixels(rem_size),
11398                cx,
11399            )
11400        });
11401        self.style = Some(style);
11402    }
11403
11404    pub fn style(&self) -> Option<&EditorStyle> {
11405        self.style.as_ref()
11406    }
11407
11408    // Called by the element. This method is not designed to be called outside of the editor
11409    // element's layout code because it does not notify when rewrapping is computed synchronously.
11410    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
11411        self.display_map
11412            .update(cx, |map, cx| map.set_wrap_width(width, cx))
11413    }
11414
11415    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
11416        if self.soft_wrap_mode_override.is_some() {
11417            self.soft_wrap_mode_override.take();
11418        } else {
11419            let soft_wrap = match self.soft_wrap_mode(cx) {
11420                SoftWrap::GitDiff => return,
11421                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
11422                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
11423                    language_settings::SoftWrap::None
11424                }
11425            };
11426            self.soft_wrap_mode_override = Some(soft_wrap);
11427        }
11428        cx.notify();
11429    }
11430
11431    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, cx: &mut ViewContext<Self>) {
11432        let Some(workspace) = self.workspace() else {
11433            return;
11434        };
11435        let fs = workspace.read(cx).app_state().fs.clone();
11436        let current_show = TabBarSettings::get_global(cx).show;
11437        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
11438            setting.show = Some(!current_show);
11439        });
11440    }
11441
11442    pub fn toggle_indent_guides(&mut self, _: &ToggleIndentGuides, cx: &mut ViewContext<Self>) {
11443        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
11444            self.buffer
11445                .read(cx)
11446                .settings_at(0, cx)
11447                .indent_guides
11448                .enabled
11449        });
11450        self.show_indent_guides = Some(!currently_enabled);
11451        cx.notify();
11452    }
11453
11454    fn should_show_indent_guides(&self) -> Option<bool> {
11455        self.show_indent_guides
11456    }
11457
11458    pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext<Self>) {
11459        let mut editor_settings = EditorSettings::get_global(cx).clone();
11460        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
11461        EditorSettings::override_global(editor_settings, cx);
11462    }
11463
11464    pub fn should_use_relative_line_numbers(&self, cx: &WindowContext) -> bool {
11465        self.use_relative_line_numbers
11466            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
11467    }
11468
11469    pub fn toggle_relative_line_numbers(
11470        &mut self,
11471        _: &ToggleRelativeLineNumbers,
11472        cx: &mut ViewContext<Self>,
11473    ) {
11474        let is_relative = self.should_use_relative_line_numbers(cx);
11475        self.set_relative_line_number(Some(!is_relative), cx)
11476    }
11477
11478    pub fn set_relative_line_number(
11479        &mut self,
11480        is_relative: Option<bool>,
11481        cx: &mut ViewContext<Self>,
11482    ) {
11483        self.use_relative_line_numbers = is_relative;
11484        cx.notify();
11485    }
11486
11487    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
11488        self.show_gutter = show_gutter;
11489        cx.notify();
11490    }
11491
11492    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut ViewContext<Self>) {
11493        self.show_line_numbers = Some(show_line_numbers);
11494        cx.notify();
11495    }
11496
11497    pub fn set_show_git_diff_gutter(
11498        &mut self,
11499        show_git_diff_gutter: bool,
11500        cx: &mut ViewContext<Self>,
11501    ) {
11502        self.show_git_diff_gutter = Some(show_git_diff_gutter);
11503        cx.notify();
11504    }
11505
11506    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut ViewContext<Self>) {
11507        self.show_code_actions = Some(show_code_actions);
11508        cx.notify();
11509    }
11510
11511    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut ViewContext<Self>) {
11512        self.show_runnables = Some(show_runnables);
11513        cx.notify();
11514    }
11515
11516    pub fn set_masked(&mut self, masked: bool, cx: &mut ViewContext<Self>) {
11517        if self.display_map.read(cx).masked != masked {
11518            self.display_map.update(cx, |map, _| map.masked = masked);
11519        }
11520        cx.notify()
11521    }
11522
11523    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut ViewContext<Self>) {
11524        self.show_wrap_guides = Some(show_wrap_guides);
11525        cx.notify();
11526    }
11527
11528    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut ViewContext<Self>) {
11529        self.show_indent_guides = Some(show_indent_guides);
11530        cx.notify();
11531    }
11532
11533    pub fn working_directory(&self, cx: &WindowContext) -> Option<PathBuf> {
11534        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
11535            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
11536                if let Some(dir) = file.abs_path(cx).parent() {
11537                    return Some(dir.to_owned());
11538                }
11539            }
11540
11541            if let Some(project_path) = buffer.read(cx).project_path(cx) {
11542                return Some(project_path.path.to_path_buf());
11543            }
11544        }
11545
11546        None
11547    }
11548
11549    fn target_file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn language::LocalFile> {
11550        self.active_excerpt(cx)?
11551            .1
11552            .read(cx)
11553            .file()
11554            .and_then(|f| f.as_local())
11555    }
11556
11557    pub fn reveal_in_finder(&mut self, _: &RevealInFileManager, cx: &mut ViewContext<Self>) {
11558        if let Some(target) = self.target_file(cx) {
11559            cx.reveal_path(&target.abs_path(cx));
11560        }
11561    }
11562
11563    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
11564        if let Some(file) = self.target_file(cx) {
11565            if let Some(path) = file.abs_path(cx).to_str() {
11566                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
11567            }
11568        }
11569    }
11570
11571    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
11572        if let Some(file) = self.target_file(cx) {
11573            if let Some(path) = file.path().to_str() {
11574                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
11575            }
11576        }
11577    }
11578
11579    pub fn toggle_git_blame(&mut self, _: &ToggleGitBlame, cx: &mut ViewContext<Self>) {
11580        self.show_git_blame_gutter = !self.show_git_blame_gutter;
11581
11582        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
11583            self.start_git_blame(true, cx);
11584        }
11585
11586        cx.notify();
11587    }
11588
11589    pub fn toggle_git_blame_inline(
11590        &mut self,
11591        _: &ToggleGitBlameInline,
11592        cx: &mut ViewContext<Self>,
11593    ) {
11594        self.toggle_git_blame_inline_internal(true, cx);
11595        cx.notify();
11596    }
11597
11598    pub fn git_blame_inline_enabled(&self) -> bool {
11599        self.git_blame_inline_enabled
11600    }
11601
11602    pub fn toggle_selection_menu(&mut self, _: &ToggleSelectionMenu, cx: &mut ViewContext<Self>) {
11603        self.show_selection_menu = self
11604            .show_selection_menu
11605            .map(|show_selections_menu| !show_selections_menu)
11606            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
11607
11608        cx.notify();
11609    }
11610
11611    pub fn selection_menu_enabled(&self, cx: &AppContext) -> bool {
11612        self.show_selection_menu
11613            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
11614    }
11615
11616    fn start_git_blame(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
11617        if let Some(project) = self.project.as_ref() {
11618            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
11619                return;
11620            };
11621
11622            if buffer.read(cx).file().is_none() {
11623                return;
11624            }
11625
11626            let focused = self.focus_handle(cx).contains_focused(cx);
11627
11628            let project = project.clone();
11629            let blame =
11630                cx.new_model(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
11631            self.blame_subscription = Some(cx.observe(&blame, |_, _, cx| cx.notify()));
11632            self.blame = Some(blame);
11633        }
11634    }
11635
11636    fn toggle_git_blame_inline_internal(
11637        &mut self,
11638        user_triggered: bool,
11639        cx: &mut ViewContext<Self>,
11640    ) {
11641        if self.git_blame_inline_enabled {
11642            self.git_blame_inline_enabled = false;
11643            self.show_git_blame_inline = false;
11644            self.show_git_blame_inline_delay_task.take();
11645        } else {
11646            self.git_blame_inline_enabled = true;
11647            self.start_git_blame_inline(user_triggered, cx);
11648        }
11649
11650        cx.notify();
11651    }
11652
11653    fn start_git_blame_inline(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
11654        self.start_git_blame(user_triggered, cx);
11655
11656        if ProjectSettings::get_global(cx)
11657            .git
11658            .inline_blame_delay()
11659            .is_some()
11660        {
11661            self.start_inline_blame_timer(cx);
11662        } else {
11663            self.show_git_blame_inline = true
11664        }
11665    }
11666
11667    pub fn blame(&self) -> Option<&Model<GitBlame>> {
11668        self.blame.as_ref()
11669    }
11670
11671    pub fn render_git_blame_gutter(&mut self, cx: &mut WindowContext) -> bool {
11672        self.show_git_blame_gutter && self.has_blame_entries(cx)
11673    }
11674
11675    pub fn render_git_blame_inline(&mut self, cx: &mut WindowContext) -> bool {
11676        self.show_git_blame_inline
11677            && self.focus_handle.is_focused(cx)
11678            && !self.newest_selection_head_on_empty_line(cx)
11679            && self.has_blame_entries(cx)
11680    }
11681
11682    fn has_blame_entries(&self, cx: &mut WindowContext) -> bool {
11683        self.blame()
11684            .map_or(false, |blame| blame.read(cx).has_generated_entries())
11685    }
11686
11687    fn newest_selection_head_on_empty_line(&mut self, cx: &mut WindowContext) -> bool {
11688        let cursor_anchor = self.selections.newest_anchor().head();
11689
11690        let snapshot = self.buffer.read(cx).snapshot(cx);
11691        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
11692
11693        snapshot.line_len(buffer_row) == 0
11694    }
11695
11696    fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<url::Url>> {
11697        let buffer_and_selection = maybe!({
11698            let selection = self.selections.newest::<Point>(cx);
11699            let selection_range = selection.range();
11700
11701            let (buffer, selection) = if let Some(buffer) = self.buffer().read(cx).as_singleton() {
11702                (buffer, selection_range.start.row..selection_range.end.row)
11703            } else {
11704                let buffer_ranges = self
11705                    .buffer()
11706                    .read(cx)
11707                    .range_to_buffer_ranges(selection_range, cx);
11708
11709                let (buffer, range, _) = if selection.reversed {
11710                    buffer_ranges.first()
11711                } else {
11712                    buffer_ranges.last()
11713                }?;
11714
11715                let snapshot = buffer.read(cx).snapshot();
11716                let selection = text::ToPoint::to_point(&range.start, &snapshot).row
11717                    ..text::ToPoint::to_point(&range.end, &snapshot).row;
11718                (buffer.clone(), selection)
11719            };
11720
11721            Some((buffer, selection))
11722        });
11723
11724        let Some((buffer, selection)) = buffer_and_selection else {
11725            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
11726        };
11727
11728        let Some(project) = self.project.as_ref() else {
11729            return Task::ready(Err(anyhow!("editor does not have project")));
11730        };
11731
11732        project.update(cx, |project, cx| {
11733            project.get_permalink_to_line(&buffer, selection, cx)
11734        })
11735    }
11736
11737    pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
11738        let permalink_task = self.get_permalink_to_line(cx);
11739        let workspace = self.workspace();
11740
11741        cx.spawn(|_, mut cx| async move {
11742            match permalink_task.await {
11743                Ok(permalink) => {
11744                    cx.update(|cx| {
11745                        cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
11746                    })
11747                    .ok();
11748                }
11749                Err(err) => {
11750                    let message = format!("Failed to copy permalink: {err}");
11751
11752                    Err::<(), anyhow::Error>(err).log_err();
11753
11754                    if let Some(workspace) = workspace {
11755                        workspace
11756                            .update(&mut cx, |workspace, cx| {
11757                                struct CopyPermalinkToLine;
11758
11759                                workspace.show_toast(
11760                                    Toast::new(
11761                                        NotificationId::unique::<CopyPermalinkToLine>(),
11762                                        message,
11763                                    ),
11764                                    cx,
11765                                )
11766                            })
11767                            .ok();
11768                    }
11769                }
11770            }
11771        })
11772        .detach();
11773    }
11774
11775    pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext<Self>) {
11776        let selection = self.selections.newest::<Point>(cx).start.row + 1;
11777        if let Some(file) = self.target_file(cx) {
11778            if let Some(path) = file.path().to_str() {
11779                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
11780            }
11781        }
11782    }
11783
11784    pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
11785        let permalink_task = self.get_permalink_to_line(cx);
11786        let workspace = self.workspace();
11787
11788        cx.spawn(|_, mut cx| async move {
11789            match permalink_task.await {
11790                Ok(permalink) => {
11791                    cx.update(|cx| {
11792                        cx.open_url(permalink.as_ref());
11793                    })
11794                    .ok();
11795                }
11796                Err(err) => {
11797                    let message = format!("Failed to open permalink: {err}");
11798
11799                    Err::<(), anyhow::Error>(err).log_err();
11800
11801                    if let Some(workspace) = workspace {
11802                        workspace
11803                            .update(&mut cx, |workspace, cx| {
11804                                struct OpenPermalinkToLine;
11805
11806                                workspace.show_toast(
11807                                    Toast::new(
11808                                        NotificationId::unique::<OpenPermalinkToLine>(),
11809                                        message,
11810                                    ),
11811                                    cx,
11812                                )
11813                            })
11814                            .ok();
11815                    }
11816                }
11817            }
11818        })
11819        .detach();
11820    }
11821
11822    /// Adds a row highlight for the given range. If a row has multiple highlights, the
11823    /// last highlight added will be used.
11824    ///
11825    /// If the range ends at the beginning of a line, then that line will not be highlighted.
11826    pub fn highlight_rows<T: 'static>(
11827        &mut self,
11828        range: Range<Anchor>,
11829        color: Hsla,
11830        should_autoscroll: bool,
11831        cx: &mut ViewContext<Self>,
11832    ) {
11833        let snapshot = self.buffer().read(cx).snapshot(cx);
11834        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
11835        let ix = row_highlights.binary_search_by(|highlight| {
11836            Ordering::Equal
11837                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
11838                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
11839        });
11840
11841        if let Err(mut ix) = ix {
11842            let index = post_inc(&mut self.highlight_order);
11843
11844            // If this range intersects with the preceding highlight, then merge it with
11845            // the preceding highlight. Otherwise insert a new highlight.
11846            let mut merged = false;
11847            if ix > 0 {
11848                let prev_highlight = &mut row_highlights[ix - 1];
11849                if prev_highlight
11850                    .range
11851                    .end
11852                    .cmp(&range.start, &snapshot)
11853                    .is_ge()
11854                {
11855                    ix -= 1;
11856                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
11857                        prev_highlight.range.end = range.end;
11858                    }
11859                    merged = true;
11860                    prev_highlight.index = index;
11861                    prev_highlight.color = color;
11862                    prev_highlight.should_autoscroll = should_autoscroll;
11863                }
11864            }
11865
11866            if !merged {
11867                row_highlights.insert(
11868                    ix,
11869                    RowHighlight {
11870                        range: range.clone(),
11871                        index,
11872                        color,
11873                        should_autoscroll,
11874                    },
11875                );
11876            }
11877
11878            // If any of the following highlights intersect with this one, merge them.
11879            while let Some(next_highlight) = row_highlights.get(ix + 1) {
11880                let highlight = &row_highlights[ix];
11881                if next_highlight
11882                    .range
11883                    .start
11884                    .cmp(&highlight.range.end, &snapshot)
11885                    .is_le()
11886                {
11887                    if next_highlight
11888                        .range
11889                        .end
11890                        .cmp(&highlight.range.end, &snapshot)
11891                        .is_gt()
11892                    {
11893                        row_highlights[ix].range.end = next_highlight.range.end;
11894                    }
11895                    row_highlights.remove(ix + 1);
11896                } else {
11897                    break;
11898                }
11899            }
11900        }
11901    }
11902
11903    /// Remove any highlighted row ranges of the given type that intersect the
11904    /// given ranges.
11905    pub fn remove_highlighted_rows<T: 'static>(
11906        &mut self,
11907        ranges_to_remove: Vec<Range<Anchor>>,
11908        cx: &mut ViewContext<Self>,
11909    ) {
11910        let snapshot = self.buffer().read(cx).snapshot(cx);
11911        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
11912        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
11913        row_highlights.retain(|highlight| {
11914            while let Some(range_to_remove) = ranges_to_remove.peek() {
11915                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
11916                    Ordering::Less | Ordering::Equal => {
11917                        ranges_to_remove.next();
11918                    }
11919                    Ordering::Greater => {
11920                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
11921                            Ordering::Less | Ordering::Equal => {
11922                                return false;
11923                            }
11924                            Ordering::Greater => break,
11925                        }
11926                    }
11927                }
11928            }
11929
11930            true
11931        })
11932    }
11933
11934    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
11935    pub fn clear_row_highlights<T: 'static>(&mut self) {
11936        self.highlighted_rows.remove(&TypeId::of::<T>());
11937    }
11938
11939    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
11940    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
11941        self.highlighted_rows
11942            .get(&TypeId::of::<T>())
11943            .map_or(&[] as &[_], |vec| vec.as_slice())
11944            .iter()
11945            .map(|highlight| (highlight.range.clone(), highlight.color))
11946    }
11947
11948    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
11949    /// Rerturns a map of display rows that are highlighted and their corresponding highlight color.
11950    /// Allows to ignore certain kinds of highlights.
11951    pub fn highlighted_display_rows(
11952        &mut self,
11953        cx: &mut WindowContext,
11954    ) -> BTreeMap<DisplayRow, Hsla> {
11955        let snapshot = self.snapshot(cx);
11956        let mut used_highlight_orders = HashMap::default();
11957        self.highlighted_rows
11958            .iter()
11959            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
11960            .fold(
11961                BTreeMap::<DisplayRow, Hsla>::new(),
11962                |mut unique_rows, highlight| {
11963                    let start = highlight.range.start.to_display_point(&snapshot);
11964                    let end = highlight.range.end.to_display_point(&snapshot);
11965                    let start_row = start.row().0;
11966                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
11967                        && end.column() == 0
11968                    {
11969                        end.row().0.saturating_sub(1)
11970                    } else {
11971                        end.row().0
11972                    };
11973                    for row in start_row..=end_row {
11974                        let used_index =
11975                            used_highlight_orders.entry(row).or_insert(highlight.index);
11976                        if highlight.index >= *used_index {
11977                            *used_index = highlight.index;
11978                            unique_rows.insert(DisplayRow(row), highlight.color);
11979                        }
11980                    }
11981                    unique_rows
11982                },
11983            )
11984    }
11985
11986    pub fn highlighted_display_row_for_autoscroll(
11987        &self,
11988        snapshot: &DisplaySnapshot,
11989    ) -> Option<DisplayRow> {
11990        self.highlighted_rows
11991            .values()
11992            .flat_map(|highlighted_rows| highlighted_rows.iter())
11993            .filter_map(|highlight| {
11994                if highlight.should_autoscroll {
11995                    Some(highlight.range.start.to_display_point(snapshot).row())
11996                } else {
11997                    None
11998                }
11999            })
12000            .min()
12001    }
12002
12003    pub fn set_search_within_ranges(
12004        &mut self,
12005        ranges: &[Range<Anchor>],
12006        cx: &mut ViewContext<Self>,
12007    ) {
12008        self.highlight_background::<SearchWithinRange>(
12009            ranges,
12010            |colors| colors.editor_document_highlight_read_background,
12011            cx,
12012        )
12013    }
12014
12015    pub fn set_breadcrumb_header(&mut self, new_header: String) {
12016        self.breadcrumb_header = Some(new_header);
12017    }
12018
12019    pub fn clear_search_within_ranges(&mut self, cx: &mut ViewContext<Self>) {
12020        self.clear_background_highlights::<SearchWithinRange>(cx);
12021    }
12022
12023    pub fn highlight_background<T: 'static>(
12024        &mut self,
12025        ranges: &[Range<Anchor>],
12026        color_fetcher: fn(&ThemeColors) -> Hsla,
12027        cx: &mut ViewContext<Self>,
12028    ) {
12029        self.background_highlights
12030            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
12031        self.scrollbar_marker_state.dirty = true;
12032        cx.notify();
12033    }
12034
12035    pub fn clear_background_highlights<T: 'static>(
12036        &mut self,
12037        cx: &mut ViewContext<Self>,
12038    ) -> Option<BackgroundHighlight> {
12039        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
12040        if !text_highlights.1.is_empty() {
12041            self.scrollbar_marker_state.dirty = true;
12042            cx.notify();
12043        }
12044        Some(text_highlights)
12045    }
12046
12047    pub fn highlight_gutter<T: 'static>(
12048        &mut self,
12049        ranges: &[Range<Anchor>],
12050        color_fetcher: fn(&AppContext) -> Hsla,
12051        cx: &mut ViewContext<Self>,
12052    ) {
12053        self.gutter_highlights
12054            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
12055        cx.notify();
12056    }
12057
12058    pub fn clear_gutter_highlights<T: 'static>(
12059        &mut self,
12060        cx: &mut ViewContext<Self>,
12061    ) -> Option<GutterHighlight> {
12062        cx.notify();
12063        self.gutter_highlights.remove(&TypeId::of::<T>())
12064    }
12065
12066    #[cfg(feature = "test-support")]
12067    pub fn all_text_background_highlights(
12068        &mut self,
12069        cx: &mut ViewContext<Self>,
12070    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
12071        let snapshot = self.snapshot(cx);
12072        let buffer = &snapshot.buffer_snapshot;
12073        let start = buffer.anchor_before(0);
12074        let end = buffer.anchor_after(buffer.len());
12075        let theme = cx.theme().colors();
12076        self.background_highlights_in_range(start..end, &snapshot, theme)
12077    }
12078
12079    #[cfg(feature = "test-support")]
12080    pub fn search_background_highlights(
12081        &mut self,
12082        cx: &mut ViewContext<Self>,
12083    ) -> Vec<Range<Point>> {
12084        let snapshot = self.buffer().read(cx).snapshot(cx);
12085
12086        let highlights = self
12087            .background_highlights
12088            .get(&TypeId::of::<items::BufferSearchHighlights>());
12089
12090        if let Some((_color, ranges)) = highlights {
12091            ranges
12092                .iter()
12093                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
12094                .collect_vec()
12095        } else {
12096            vec![]
12097        }
12098    }
12099
12100    fn document_highlights_for_position<'a>(
12101        &'a self,
12102        position: Anchor,
12103        buffer: &'a MultiBufferSnapshot,
12104    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
12105        let read_highlights = self
12106            .background_highlights
12107            .get(&TypeId::of::<DocumentHighlightRead>())
12108            .map(|h| &h.1);
12109        let write_highlights = self
12110            .background_highlights
12111            .get(&TypeId::of::<DocumentHighlightWrite>())
12112            .map(|h| &h.1);
12113        let left_position = position.bias_left(buffer);
12114        let right_position = position.bias_right(buffer);
12115        read_highlights
12116            .into_iter()
12117            .chain(write_highlights)
12118            .flat_map(move |ranges| {
12119                let start_ix = match ranges.binary_search_by(|probe| {
12120                    let cmp = probe.end.cmp(&left_position, buffer);
12121                    if cmp.is_ge() {
12122                        Ordering::Greater
12123                    } else {
12124                        Ordering::Less
12125                    }
12126                }) {
12127                    Ok(i) | Err(i) => i,
12128                };
12129
12130                ranges[start_ix..]
12131                    .iter()
12132                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
12133            })
12134    }
12135
12136    pub fn has_background_highlights<T: 'static>(&self) -> bool {
12137        self.background_highlights
12138            .get(&TypeId::of::<T>())
12139            .map_or(false, |(_, highlights)| !highlights.is_empty())
12140    }
12141
12142    pub fn background_highlights_in_range(
12143        &self,
12144        search_range: Range<Anchor>,
12145        display_snapshot: &DisplaySnapshot,
12146        theme: &ThemeColors,
12147    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
12148        let mut results = Vec::new();
12149        for (color_fetcher, ranges) in self.background_highlights.values() {
12150            let color = color_fetcher(theme);
12151            let start_ix = match ranges.binary_search_by(|probe| {
12152                let cmp = probe
12153                    .end
12154                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
12155                if cmp.is_gt() {
12156                    Ordering::Greater
12157                } else {
12158                    Ordering::Less
12159                }
12160            }) {
12161                Ok(i) | Err(i) => i,
12162            };
12163            for range in &ranges[start_ix..] {
12164                if range
12165                    .start
12166                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
12167                    .is_ge()
12168                {
12169                    break;
12170                }
12171
12172                let start = range.start.to_display_point(display_snapshot);
12173                let end = range.end.to_display_point(display_snapshot);
12174                results.push((start..end, color))
12175            }
12176        }
12177        results
12178    }
12179
12180    pub fn background_highlight_row_ranges<T: 'static>(
12181        &self,
12182        search_range: Range<Anchor>,
12183        display_snapshot: &DisplaySnapshot,
12184        count: usize,
12185    ) -> Vec<RangeInclusive<DisplayPoint>> {
12186        let mut results = Vec::new();
12187        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
12188            return vec![];
12189        };
12190
12191        let start_ix = match ranges.binary_search_by(|probe| {
12192            let cmp = probe
12193                .end
12194                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
12195            if cmp.is_gt() {
12196                Ordering::Greater
12197            } else {
12198                Ordering::Less
12199            }
12200        }) {
12201            Ok(i) | Err(i) => i,
12202        };
12203        let mut push_region = |start: Option<Point>, end: Option<Point>| {
12204            if let (Some(start_display), Some(end_display)) = (start, end) {
12205                results.push(
12206                    start_display.to_display_point(display_snapshot)
12207                        ..=end_display.to_display_point(display_snapshot),
12208                );
12209            }
12210        };
12211        let mut start_row: Option<Point> = None;
12212        let mut end_row: Option<Point> = None;
12213        if ranges.len() > count {
12214            return Vec::new();
12215        }
12216        for range in &ranges[start_ix..] {
12217            if range
12218                .start
12219                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
12220                .is_ge()
12221            {
12222                break;
12223            }
12224            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
12225            if let Some(current_row) = &end_row {
12226                if end.row == current_row.row {
12227                    continue;
12228                }
12229            }
12230            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
12231            if start_row.is_none() {
12232                assert_eq!(end_row, None);
12233                start_row = Some(start);
12234                end_row = Some(end);
12235                continue;
12236            }
12237            if let Some(current_end) = end_row.as_mut() {
12238                if start.row > current_end.row + 1 {
12239                    push_region(start_row, end_row);
12240                    start_row = Some(start);
12241                    end_row = Some(end);
12242                } else {
12243                    // Merge two hunks.
12244                    *current_end = end;
12245                }
12246            } else {
12247                unreachable!();
12248            }
12249        }
12250        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
12251        push_region(start_row, end_row);
12252        results
12253    }
12254
12255    pub fn gutter_highlights_in_range(
12256        &self,
12257        search_range: Range<Anchor>,
12258        display_snapshot: &DisplaySnapshot,
12259        cx: &AppContext,
12260    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
12261        let mut results = Vec::new();
12262        for (color_fetcher, ranges) in self.gutter_highlights.values() {
12263            let color = color_fetcher(cx);
12264            let start_ix = match ranges.binary_search_by(|probe| {
12265                let cmp = probe
12266                    .end
12267                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
12268                if cmp.is_gt() {
12269                    Ordering::Greater
12270                } else {
12271                    Ordering::Less
12272                }
12273            }) {
12274                Ok(i) | Err(i) => i,
12275            };
12276            for range in &ranges[start_ix..] {
12277                if range
12278                    .start
12279                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
12280                    .is_ge()
12281                {
12282                    break;
12283                }
12284
12285                let start = range.start.to_display_point(display_snapshot);
12286                let end = range.end.to_display_point(display_snapshot);
12287                results.push((start..end, color))
12288            }
12289        }
12290        results
12291    }
12292
12293    /// Get the text ranges corresponding to the redaction query
12294    pub fn redacted_ranges(
12295        &self,
12296        search_range: Range<Anchor>,
12297        display_snapshot: &DisplaySnapshot,
12298        cx: &WindowContext,
12299    ) -> Vec<Range<DisplayPoint>> {
12300        display_snapshot
12301            .buffer_snapshot
12302            .redacted_ranges(search_range, |file| {
12303                if let Some(file) = file {
12304                    file.is_private()
12305                        && EditorSettings::get(
12306                            Some(SettingsLocation {
12307                                worktree_id: file.worktree_id(cx),
12308                                path: file.path().as_ref(),
12309                            }),
12310                            cx,
12311                        )
12312                        .redact_private_values
12313                } else {
12314                    false
12315                }
12316            })
12317            .map(|range| {
12318                range.start.to_display_point(display_snapshot)
12319                    ..range.end.to_display_point(display_snapshot)
12320            })
12321            .collect()
12322    }
12323
12324    pub fn highlight_text<T: 'static>(
12325        &mut self,
12326        ranges: Vec<Range<Anchor>>,
12327        style: HighlightStyle,
12328        cx: &mut ViewContext<Self>,
12329    ) {
12330        self.display_map.update(cx, |map, _| {
12331            map.highlight_text(TypeId::of::<T>(), ranges, style)
12332        });
12333        cx.notify();
12334    }
12335
12336    pub(crate) fn highlight_inlays<T: 'static>(
12337        &mut self,
12338        highlights: Vec<InlayHighlight>,
12339        style: HighlightStyle,
12340        cx: &mut ViewContext<Self>,
12341    ) {
12342        self.display_map.update(cx, |map, _| {
12343            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
12344        });
12345        cx.notify();
12346    }
12347
12348    pub fn text_highlights<'a, T: 'static>(
12349        &'a self,
12350        cx: &'a AppContext,
12351    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
12352        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
12353    }
12354
12355    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
12356        let cleared = self
12357            .display_map
12358            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
12359        if cleared {
12360            cx.notify();
12361        }
12362    }
12363
12364    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
12365        (self.read_only(cx) || self.blink_manager.read(cx).visible())
12366            && self.focus_handle.is_focused(cx)
12367    }
12368
12369    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut ViewContext<Self>) {
12370        self.show_cursor_when_unfocused = is_enabled;
12371        cx.notify();
12372    }
12373
12374    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
12375        cx.notify();
12376    }
12377
12378    fn on_buffer_event(
12379        &mut self,
12380        multibuffer: Model<MultiBuffer>,
12381        event: &multi_buffer::Event,
12382        cx: &mut ViewContext<Self>,
12383    ) {
12384        match event {
12385            multi_buffer::Event::Edited {
12386                singleton_buffer_edited,
12387            } => {
12388                self.scrollbar_marker_state.dirty = true;
12389                self.active_indent_guides_state.dirty = true;
12390                self.refresh_active_diagnostics(cx);
12391                self.refresh_code_actions(cx);
12392                if self.has_active_inline_completion(cx) {
12393                    self.update_visible_inline_completion(cx);
12394                }
12395                cx.emit(EditorEvent::BufferEdited);
12396                cx.emit(SearchEvent::MatchesInvalidated);
12397                if *singleton_buffer_edited {
12398                    if let Some(project) = &self.project {
12399                        let project = project.read(cx);
12400                        #[allow(clippy::mutable_key_type)]
12401                        let languages_affected = multibuffer
12402                            .read(cx)
12403                            .all_buffers()
12404                            .into_iter()
12405                            .filter_map(|buffer| {
12406                                let buffer = buffer.read(cx);
12407                                let language = buffer.language()?;
12408                                if project.is_local()
12409                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
12410                                {
12411                                    None
12412                                } else {
12413                                    Some(language)
12414                                }
12415                            })
12416                            .cloned()
12417                            .collect::<HashSet<_>>();
12418                        if !languages_affected.is_empty() {
12419                            self.refresh_inlay_hints(
12420                                InlayHintRefreshReason::BufferEdited(languages_affected),
12421                                cx,
12422                            );
12423                        }
12424                    }
12425                }
12426
12427                let Some(project) = &self.project else { return };
12428                let (telemetry, is_via_ssh) = {
12429                    let project = project.read(cx);
12430                    let telemetry = project.client().telemetry().clone();
12431                    let is_via_ssh = project.is_via_ssh();
12432                    (telemetry, is_via_ssh)
12433                };
12434                refresh_linked_ranges(self, cx);
12435                telemetry.log_edit_event("editor", is_via_ssh);
12436            }
12437            multi_buffer::Event::ExcerptsAdded {
12438                buffer,
12439                predecessor,
12440                excerpts,
12441            } => {
12442                self.tasks_update_task = Some(self.refresh_runnables(cx));
12443                cx.emit(EditorEvent::ExcerptsAdded {
12444                    buffer: buffer.clone(),
12445                    predecessor: *predecessor,
12446                    excerpts: excerpts.clone(),
12447                });
12448                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
12449            }
12450            multi_buffer::Event::ExcerptsRemoved { ids } => {
12451                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
12452                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
12453            }
12454            multi_buffer::Event::ExcerptsEdited { ids } => {
12455                cx.emit(EditorEvent::ExcerptsEdited { ids: ids.clone() })
12456            }
12457            multi_buffer::Event::ExcerptsExpanded { ids } => {
12458                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
12459            }
12460            multi_buffer::Event::Reparsed(buffer_id) => {
12461                self.tasks_update_task = Some(self.refresh_runnables(cx));
12462
12463                cx.emit(EditorEvent::Reparsed(*buffer_id));
12464            }
12465            multi_buffer::Event::LanguageChanged(buffer_id) => {
12466                linked_editing_ranges::refresh_linked_ranges(self, cx);
12467                cx.emit(EditorEvent::Reparsed(*buffer_id));
12468                cx.notify();
12469            }
12470            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
12471            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
12472            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
12473                cx.emit(EditorEvent::TitleChanged)
12474            }
12475            multi_buffer::Event::DiffBaseChanged => {
12476                self.scrollbar_marker_state.dirty = true;
12477                cx.emit(EditorEvent::DiffBaseChanged);
12478                cx.notify();
12479            }
12480            multi_buffer::Event::DiffUpdated { buffer } => {
12481                self.sync_expanded_diff_hunks(buffer.clone(), cx);
12482                cx.notify();
12483            }
12484            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
12485            multi_buffer::Event::DiagnosticsUpdated => {
12486                self.refresh_active_diagnostics(cx);
12487                self.scrollbar_marker_state.dirty = true;
12488                cx.notify();
12489            }
12490            _ => {}
12491        };
12492    }
12493
12494    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
12495        cx.notify();
12496    }
12497
12498    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
12499        self.tasks_update_task = Some(self.refresh_runnables(cx));
12500        self.refresh_inline_completion(true, false, cx);
12501        self.refresh_inlay_hints(
12502            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
12503                self.selections.newest_anchor().head(),
12504                &self.buffer.read(cx).snapshot(cx),
12505                cx,
12506            )),
12507            cx,
12508        );
12509
12510        let old_cursor_shape = self.cursor_shape;
12511
12512        {
12513            let editor_settings = EditorSettings::get_global(cx);
12514            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
12515            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
12516            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
12517        }
12518
12519        if old_cursor_shape != self.cursor_shape {
12520            cx.emit(EditorEvent::CursorShapeChanged);
12521        }
12522
12523        let project_settings = ProjectSettings::get_global(cx);
12524        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
12525
12526        if self.mode == EditorMode::Full {
12527            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
12528            if self.git_blame_inline_enabled != inline_blame_enabled {
12529                self.toggle_git_blame_inline_internal(false, cx);
12530            }
12531        }
12532
12533        cx.notify();
12534    }
12535
12536    pub fn set_searchable(&mut self, searchable: bool) {
12537        self.searchable = searchable;
12538    }
12539
12540    pub fn searchable(&self) -> bool {
12541        self.searchable
12542    }
12543
12544    fn open_proposed_changes_editor(
12545        &mut self,
12546        _: &OpenProposedChangesEditor,
12547        cx: &mut ViewContext<Self>,
12548    ) {
12549        let Some(workspace) = self.workspace() else {
12550            cx.propagate();
12551            return;
12552        };
12553
12554        let selections = self.selections.all::<usize>(cx);
12555        let buffer = self.buffer.read(cx);
12556        let mut new_selections_by_buffer = HashMap::default();
12557        for selection in selections {
12558            for (buffer, range, _) in
12559                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
12560            {
12561                let mut range = range.to_point(buffer.read(cx));
12562                range.start.column = 0;
12563                range.end.column = buffer.read(cx).line_len(range.end.row);
12564                new_selections_by_buffer
12565                    .entry(buffer)
12566                    .or_insert(Vec::new())
12567                    .push(range)
12568            }
12569        }
12570
12571        let proposed_changes_buffers = new_selections_by_buffer
12572            .into_iter()
12573            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
12574            .collect::<Vec<_>>();
12575        let proposed_changes_editor = cx.new_view(|cx| {
12576            ProposedChangesEditor::new(
12577                "Proposed changes",
12578                proposed_changes_buffers,
12579                self.project.clone(),
12580                cx,
12581            )
12582        });
12583
12584        cx.window_context().defer(move |cx| {
12585            workspace.update(cx, |workspace, cx| {
12586                workspace.active_pane().update(cx, |pane, cx| {
12587                    pane.add_item(Box::new(proposed_changes_editor), true, true, None, cx);
12588                });
12589            });
12590        });
12591    }
12592
12593    pub fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
12594        self.open_excerpts_common(None, true, cx)
12595    }
12596
12597    pub fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
12598        self.open_excerpts_common(None, false, cx)
12599    }
12600
12601    fn open_excerpts_common(
12602        &mut self,
12603        jump_data: Option<JumpData>,
12604        split: bool,
12605        cx: &mut ViewContext<Self>,
12606    ) {
12607        let Some(workspace) = self.workspace() else {
12608            cx.propagate();
12609            return;
12610        };
12611
12612        if self.buffer.read(cx).is_singleton() {
12613            cx.propagate();
12614            return;
12615        }
12616
12617        let mut new_selections_by_buffer = HashMap::default();
12618        match &jump_data {
12619            Some(jump_data) => {
12620                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12621                if let Some(buffer) = multi_buffer_snapshot
12622                    .buffer_id_for_excerpt(jump_data.excerpt_id)
12623                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
12624                {
12625                    let buffer_snapshot = buffer.read(cx).snapshot();
12626                    let jump_to_point = if buffer_snapshot.can_resolve(&jump_data.anchor) {
12627                        language::ToPoint::to_point(&jump_data.anchor, &buffer_snapshot)
12628                    } else {
12629                        buffer_snapshot.clip_point(jump_data.position, Bias::Left)
12630                    };
12631                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
12632                    new_selections_by_buffer.insert(
12633                        buffer,
12634                        (
12635                            vec![jump_to_offset..jump_to_offset],
12636                            Some(jump_data.line_offset_from_top),
12637                        ),
12638                    );
12639                }
12640            }
12641            None => {
12642                let selections = self.selections.all::<usize>(cx);
12643                let buffer = self.buffer.read(cx);
12644                for selection in selections {
12645                    for (mut buffer_handle, mut range, _) in
12646                        buffer.range_to_buffer_ranges(selection.range(), cx)
12647                    {
12648                        // When editing branch buffers, jump to the corresponding location
12649                        // in their base buffer.
12650                        let buffer = buffer_handle.read(cx);
12651                        if let Some(base_buffer) = buffer.diff_base_buffer() {
12652                            range = buffer.range_to_version(range, &base_buffer.read(cx).version());
12653                            buffer_handle = base_buffer;
12654                        }
12655
12656                        if selection.reversed {
12657                            mem::swap(&mut range.start, &mut range.end);
12658                        }
12659                        new_selections_by_buffer
12660                            .entry(buffer_handle)
12661                            .or_insert((Vec::new(), None))
12662                            .0
12663                            .push(range)
12664                    }
12665                }
12666            }
12667        }
12668
12669        if new_selections_by_buffer.is_empty() {
12670            return;
12671        }
12672
12673        // We defer the pane interaction because we ourselves are a workspace item
12674        // and activating a new item causes the pane to call a method on us reentrantly,
12675        // which panics if we're on the stack.
12676        cx.window_context().defer(move |cx| {
12677            workspace.update(cx, |workspace, cx| {
12678                let pane = if split {
12679                    workspace.adjacent_pane(cx)
12680                } else {
12681                    workspace.active_pane().clone()
12682                };
12683
12684                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
12685                    let editor =
12686                        workspace.open_project_item::<Self>(pane.clone(), buffer, true, true, cx);
12687                    editor.update(cx, |editor, cx| {
12688                        let autoscroll = match scroll_offset {
12689                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
12690                            None => Autoscroll::newest(),
12691                        };
12692                        let nav_history = editor.nav_history.take();
12693                        editor.change_selections(Some(autoscroll), cx, |s| {
12694                            s.select_ranges(ranges);
12695                        });
12696                        editor.nav_history = nav_history;
12697                    });
12698                }
12699            })
12700        });
12701    }
12702
12703    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
12704        let snapshot = self.buffer.read(cx).read(cx);
12705        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
12706        Some(
12707            ranges
12708                .iter()
12709                .map(move |range| {
12710                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
12711                })
12712                .collect(),
12713        )
12714    }
12715
12716    fn selection_replacement_ranges(
12717        &self,
12718        range: Range<OffsetUtf16>,
12719        cx: &mut AppContext,
12720    ) -> Vec<Range<OffsetUtf16>> {
12721        let selections = self.selections.all::<OffsetUtf16>(cx);
12722        let newest_selection = selections
12723            .iter()
12724            .max_by_key(|selection| selection.id)
12725            .unwrap();
12726        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
12727        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
12728        let snapshot = self.buffer.read(cx).read(cx);
12729        selections
12730            .into_iter()
12731            .map(|mut selection| {
12732                selection.start.0 =
12733                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
12734                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
12735                snapshot.clip_offset_utf16(selection.start, Bias::Left)
12736                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
12737            })
12738            .collect()
12739    }
12740
12741    fn report_editor_event(
12742        &self,
12743        operation: &'static str,
12744        file_extension: Option<String>,
12745        cx: &AppContext,
12746    ) {
12747        if cfg!(any(test, feature = "test-support")) {
12748            return;
12749        }
12750
12751        let Some(project) = &self.project else { return };
12752
12753        // If None, we are in a file without an extension
12754        let file = self
12755            .buffer
12756            .read(cx)
12757            .as_singleton()
12758            .and_then(|b| b.read(cx).file());
12759        let file_extension = file_extension.or(file
12760            .as_ref()
12761            .and_then(|file| Path::new(file.file_name(cx)).extension())
12762            .and_then(|e| e.to_str())
12763            .map(|a| a.to_string()));
12764
12765        let vim_mode = cx
12766            .global::<SettingsStore>()
12767            .raw_user_settings()
12768            .get("vim_mode")
12769            == Some(&serde_json::Value::Bool(true));
12770
12771        let copilot_enabled = all_language_settings(file, cx).inline_completions.provider
12772            == language::language_settings::InlineCompletionProvider::Copilot;
12773        let copilot_enabled_for_language = self
12774            .buffer
12775            .read(cx)
12776            .settings_at(0, cx)
12777            .show_inline_completions;
12778
12779        let project = project.read(cx);
12780        let telemetry = project.client().telemetry().clone();
12781        telemetry.report_editor_event(
12782            file_extension,
12783            vim_mode,
12784            operation,
12785            copilot_enabled,
12786            copilot_enabled_for_language,
12787            project.is_via_ssh(),
12788        )
12789    }
12790
12791    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
12792    /// with each line being an array of {text, highlight} objects.
12793    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
12794        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
12795            return;
12796        };
12797
12798        #[derive(Serialize)]
12799        struct Chunk<'a> {
12800            text: String,
12801            highlight: Option<&'a str>,
12802        }
12803
12804        let snapshot = buffer.read(cx).snapshot();
12805        let range = self
12806            .selected_text_range(false, cx)
12807            .and_then(|selection| {
12808                if selection.range.is_empty() {
12809                    None
12810                } else {
12811                    Some(selection.range)
12812                }
12813            })
12814            .unwrap_or_else(|| 0..snapshot.len());
12815
12816        let chunks = snapshot.chunks(range, true);
12817        let mut lines = Vec::new();
12818        let mut line: VecDeque<Chunk> = VecDeque::new();
12819
12820        let Some(style) = self.style.as_ref() else {
12821            return;
12822        };
12823
12824        for chunk in chunks {
12825            let highlight = chunk
12826                .syntax_highlight_id
12827                .and_then(|id| id.name(&style.syntax));
12828            let mut chunk_lines = chunk.text.split('\n').peekable();
12829            while let Some(text) = chunk_lines.next() {
12830                let mut merged_with_last_token = false;
12831                if let Some(last_token) = line.back_mut() {
12832                    if last_token.highlight == highlight {
12833                        last_token.text.push_str(text);
12834                        merged_with_last_token = true;
12835                    }
12836                }
12837
12838                if !merged_with_last_token {
12839                    line.push_back(Chunk {
12840                        text: text.into(),
12841                        highlight,
12842                    });
12843                }
12844
12845                if chunk_lines.peek().is_some() {
12846                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
12847                        line.pop_front();
12848                    }
12849                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
12850                        line.pop_back();
12851                    }
12852
12853                    lines.push(mem::take(&mut line));
12854                }
12855            }
12856        }
12857
12858        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
12859            return;
12860        };
12861        cx.write_to_clipboard(ClipboardItem::new_string(lines));
12862    }
12863
12864    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
12865        &self.inlay_hint_cache
12866    }
12867
12868    pub fn replay_insert_event(
12869        &mut self,
12870        text: &str,
12871        relative_utf16_range: Option<Range<isize>>,
12872        cx: &mut ViewContext<Self>,
12873    ) {
12874        if !self.input_enabled {
12875            cx.emit(EditorEvent::InputIgnored { text: text.into() });
12876            return;
12877        }
12878        if let Some(relative_utf16_range) = relative_utf16_range {
12879            let selections = self.selections.all::<OffsetUtf16>(cx);
12880            self.change_selections(None, cx, |s| {
12881                let new_ranges = selections.into_iter().map(|range| {
12882                    let start = OffsetUtf16(
12883                        range
12884                            .head()
12885                            .0
12886                            .saturating_add_signed(relative_utf16_range.start),
12887                    );
12888                    let end = OffsetUtf16(
12889                        range
12890                            .head()
12891                            .0
12892                            .saturating_add_signed(relative_utf16_range.end),
12893                    );
12894                    start..end
12895                });
12896                s.select_ranges(new_ranges);
12897            });
12898        }
12899
12900        self.handle_input(text, cx);
12901    }
12902
12903    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
12904        let Some(provider) = self.semantics_provider.as_ref() else {
12905            return false;
12906        };
12907
12908        let mut supports = false;
12909        self.buffer().read(cx).for_each_buffer(|buffer| {
12910            supports |= provider.supports_inlay_hints(buffer, cx);
12911        });
12912        supports
12913    }
12914
12915    pub fn focus(&self, cx: &mut WindowContext) {
12916        cx.focus(&self.focus_handle)
12917    }
12918
12919    pub fn is_focused(&self, cx: &WindowContext) -> bool {
12920        self.focus_handle.is_focused(cx)
12921    }
12922
12923    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
12924        cx.emit(EditorEvent::Focused);
12925
12926        if let Some(descendant) = self
12927            .last_focused_descendant
12928            .take()
12929            .and_then(|descendant| descendant.upgrade())
12930        {
12931            cx.focus(&descendant);
12932        } else {
12933            if let Some(blame) = self.blame.as_ref() {
12934                blame.update(cx, GitBlame::focus)
12935            }
12936
12937            self.blink_manager.update(cx, BlinkManager::enable);
12938            self.show_cursor_names(cx);
12939            self.buffer.update(cx, |buffer, cx| {
12940                buffer.finalize_last_transaction(cx);
12941                if self.leader_peer_id.is_none() {
12942                    buffer.set_active_selections(
12943                        &self.selections.disjoint_anchors(),
12944                        self.selections.line_mode,
12945                        self.cursor_shape,
12946                        cx,
12947                    );
12948                }
12949            });
12950        }
12951    }
12952
12953    fn handle_focus_in(&mut self, cx: &mut ViewContext<Self>) {
12954        cx.emit(EditorEvent::FocusedIn)
12955    }
12956
12957    fn handle_focus_out(&mut self, event: FocusOutEvent, _cx: &mut ViewContext<Self>) {
12958        if event.blurred != self.focus_handle {
12959            self.last_focused_descendant = Some(event.blurred);
12960        }
12961    }
12962
12963    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
12964        self.blink_manager.update(cx, BlinkManager::disable);
12965        self.buffer
12966            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
12967
12968        if let Some(blame) = self.blame.as_ref() {
12969            blame.update(cx, GitBlame::blur)
12970        }
12971        if !self.hover_state.focused(cx) {
12972            hide_hover(self, cx);
12973        }
12974
12975        self.hide_context_menu(cx);
12976        cx.emit(EditorEvent::Blurred);
12977        cx.notify();
12978    }
12979
12980    pub fn register_action<A: Action>(
12981        &mut self,
12982        listener: impl Fn(&A, &mut WindowContext) + 'static,
12983    ) -> Subscription {
12984        let id = self.next_editor_action_id.post_inc();
12985        let listener = Arc::new(listener);
12986        self.editor_actions.borrow_mut().insert(
12987            id,
12988            Box::new(move |cx| {
12989                let cx = cx.window_context();
12990                let listener = listener.clone();
12991                cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
12992                    let action = action.downcast_ref().unwrap();
12993                    if phase == DispatchPhase::Bubble {
12994                        listener(action, cx)
12995                    }
12996                })
12997            }),
12998        );
12999
13000        let editor_actions = self.editor_actions.clone();
13001        Subscription::new(move || {
13002            editor_actions.borrow_mut().remove(&id);
13003        })
13004    }
13005
13006    pub fn file_header_size(&self) -> u32 {
13007        FILE_HEADER_HEIGHT
13008    }
13009
13010    pub fn revert(
13011        &mut self,
13012        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
13013        cx: &mut ViewContext<Self>,
13014    ) {
13015        self.buffer().update(cx, |multi_buffer, cx| {
13016            for (buffer_id, changes) in revert_changes {
13017                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13018                    buffer.update(cx, |buffer, cx| {
13019                        buffer.edit(
13020                            changes.into_iter().map(|(range, text)| {
13021                                (range, text.to_string().map(Arc::<str>::from))
13022                            }),
13023                            None,
13024                            cx,
13025                        );
13026                    });
13027                }
13028            }
13029        });
13030        self.change_selections(None, cx, |selections| selections.refresh());
13031    }
13032
13033    pub fn to_pixel_point(
13034        &mut self,
13035        source: multi_buffer::Anchor,
13036        editor_snapshot: &EditorSnapshot,
13037        cx: &mut ViewContext<Self>,
13038    ) -> Option<gpui::Point<Pixels>> {
13039        let source_point = source.to_display_point(editor_snapshot);
13040        self.display_to_pixel_point(source_point, editor_snapshot, cx)
13041    }
13042
13043    pub fn display_to_pixel_point(
13044        &mut self,
13045        source: DisplayPoint,
13046        editor_snapshot: &EditorSnapshot,
13047        cx: &mut ViewContext<Self>,
13048    ) -> Option<gpui::Point<Pixels>> {
13049        let line_height = self.style()?.text.line_height_in_pixels(cx.rem_size());
13050        let text_layout_details = self.text_layout_details(cx);
13051        let scroll_top = text_layout_details
13052            .scroll_anchor
13053            .scroll_position(editor_snapshot)
13054            .y;
13055
13056        if source.row().as_f32() < scroll_top.floor() {
13057            return None;
13058        }
13059        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
13060        let source_y = line_height * (source.row().as_f32() - scroll_top);
13061        Some(gpui::Point::new(source_x, source_y))
13062    }
13063
13064    pub fn has_active_completions_menu(&self) -> bool {
13065        self.context_menu.read().as_ref().map_or(false, |menu| {
13066            menu.visible() && matches!(menu, ContextMenu::Completions(_))
13067        })
13068    }
13069
13070    pub fn register_addon<T: Addon>(&mut self, instance: T) {
13071        self.addons
13072            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
13073    }
13074
13075    pub fn unregister_addon<T: Addon>(&mut self) {
13076        self.addons.remove(&std::any::TypeId::of::<T>());
13077    }
13078
13079    pub fn addon<T: Addon>(&self) -> Option<&T> {
13080        let type_id = std::any::TypeId::of::<T>();
13081        self.addons
13082            .get(&type_id)
13083            .and_then(|item| item.to_any().downcast_ref::<T>())
13084    }
13085}
13086
13087fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
13088    let tab_size = tab_size.get() as usize;
13089    let mut width = offset;
13090
13091    for ch in text.chars() {
13092        width += if ch == '\t' {
13093            tab_size - (width % tab_size)
13094        } else {
13095            1
13096        };
13097    }
13098
13099    width - offset
13100}
13101
13102#[cfg(test)]
13103mod tests {
13104    use super::*;
13105
13106    #[test]
13107    fn test_string_size_with_expanded_tabs() {
13108        let nz = |val| NonZeroU32::new(val).unwrap();
13109        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
13110        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
13111        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
13112        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
13113        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
13114        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
13115        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
13116        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
13117    }
13118}
13119
13120/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
13121struct WordBreakingTokenizer<'a> {
13122    input: &'a str,
13123}
13124
13125impl<'a> WordBreakingTokenizer<'a> {
13126    fn new(input: &'a str) -> Self {
13127        Self { input }
13128    }
13129}
13130
13131fn is_char_ideographic(ch: char) -> bool {
13132    use unicode_script::Script::*;
13133    use unicode_script::UnicodeScript;
13134    matches!(ch.script(), Han | Tangut | Yi)
13135}
13136
13137fn is_grapheme_ideographic(text: &str) -> bool {
13138    text.chars().any(is_char_ideographic)
13139}
13140
13141fn is_grapheme_whitespace(text: &str) -> bool {
13142    text.chars().any(|x| x.is_whitespace())
13143}
13144
13145fn should_stay_with_preceding_ideograph(text: &str) -> bool {
13146    text.chars().next().map_or(false, |ch| {
13147        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
13148    })
13149}
13150
13151#[derive(PartialEq, Eq, Debug, Clone, Copy)]
13152struct WordBreakToken<'a> {
13153    token: &'a str,
13154    grapheme_len: usize,
13155    is_whitespace: bool,
13156}
13157
13158impl<'a> Iterator for WordBreakingTokenizer<'a> {
13159    /// Yields a span, the count of graphemes in the token, and whether it was
13160    /// whitespace. Note that it also breaks at word boundaries.
13161    type Item = WordBreakToken<'a>;
13162
13163    fn next(&mut self) -> Option<Self::Item> {
13164        use unicode_segmentation::UnicodeSegmentation;
13165        if self.input.is_empty() {
13166            return None;
13167        }
13168
13169        let mut iter = self.input.graphemes(true).peekable();
13170        let mut offset = 0;
13171        let mut graphemes = 0;
13172        if let Some(first_grapheme) = iter.next() {
13173            let is_whitespace = is_grapheme_whitespace(first_grapheme);
13174            offset += first_grapheme.len();
13175            graphemes += 1;
13176            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
13177                if let Some(grapheme) = iter.peek().copied() {
13178                    if should_stay_with_preceding_ideograph(grapheme) {
13179                        offset += grapheme.len();
13180                        graphemes += 1;
13181                    }
13182                }
13183            } else {
13184                let mut words = self.input[offset..].split_word_bound_indices().peekable();
13185                let mut next_word_bound = words.peek().copied();
13186                if next_word_bound.map_or(false, |(i, _)| i == 0) {
13187                    next_word_bound = words.next();
13188                }
13189                while let Some(grapheme) = iter.peek().copied() {
13190                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
13191                        break;
13192                    };
13193                    if is_grapheme_whitespace(grapheme) != is_whitespace {
13194                        break;
13195                    };
13196                    offset += grapheme.len();
13197                    graphemes += 1;
13198                    iter.next();
13199                }
13200            }
13201            let token = &self.input[..offset];
13202            self.input = &self.input[offset..];
13203            if is_whitespace {
13204                Some(WordBreakToken {
13205                    token: " ",
13206                    grapheme_len: 1,
13207                    is_whitespace: true,
13208                })
13209            } else {
13210                Some(WordBreakToken {
13211                    token,
13212                    grapheme_len: graphemes,
13213                    is_whitespace: false,
13214                })
13215            }
13216        } else {
13217            None
13218        }
13219    }
13220}
13221
13222#[test]
13223fn test_word_breaking_tokenizer() {
13224    let tests: &[(&str, &[(&str, usize, bool)])] = &[
13225        ("", &[]),
13226        ("  ", &[(" ", 1, true)]),
13227        ("Ʒ", &[("Ʒ", 1, false)]),
13228        ("Ǽ", &[("Ǽ", 1, false)]),
13229        ("", &[("", 1, false)]),
13230        ("⋑⋑", &[("⋑⋑", 2, false)]),
13231        (
13232            "原理,进而",
13233            &[
13234                ("", 1, false),
13235                ("理,", 2, false),
13236                ("", 1, false),
13237                ("", 1, false),
13238            ],
13239        ),
13240        (
13241            "hello world",
13242            &[("hello", 5, false), (" ", 1, true), ("world", 5, false)],
13243        ),
13244        (
13245            "hello, world",
13246            &[("hello,", 6, false), (" ", 1, true), ("world", 5, false)],
13247        ),
13248        (
13249            "  hello world",
13250            &[
13251                (" ", 1, true),
13252                ("hello", 5, false),
13253                (" ", 1, true),
13254                ("world", 5, false),
13255            ],
13256        ),
13257        (
13258            "这是什么 \n 钢笔",
13259            &[
13260                ("", 1, false),
13261                ("", 1, false),
13262                ("", 1, false),
13263                ("", 1, false),
13264                (" ", 1, true),
13265                ("", 1, false),
13266                ("", 1, false),
13267            ],
13268        ),
13269        (" mutton", &[(" ", 1, true), ("mutton", 6, false)]),
13270    ];
13271
13272    for (input, result) in tests {
13273        assert_eq!(
13274            WordBreakingTokenizer::new(input).collect::<Vec<_>>(),
13275            result
13276                .iter()
13277                .copied()
13278                .map(|(token, grapheme_len, is_whitespace)| WordBreakToken {
13279                    token,
13280                    grapheme_len,
13281                    is_whitespace,
13282                })
13283                .collect::<Vec<_>>()
13284        );
13285    }
13286}
13287
13288fn wrap_with_prefix(
13289    line_prefix: String,
13290    unwrapped_text: String,
13291    wrap_column: usize,
13292    tab_size: NonZeroU32,
13293) -> String {
13294    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
13295    let mut wrapped_text = String::new();
13296    let mut current_line = line_prefix.clone();
13297
13298    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
13299    let mut current_line_len = line_prefix_len;
13300    for WordBreakToken {
13301        token,
13302        grapheme_len,
13303        is_whitespace,
13304    } in tokenizer
13305    {
13306        if current_line_len + grapheme_len > wrap_column && current_line_len != line_prefix_len {
13307            wrapped_text.push_str(current_line.trim_end());
13308            wrapped_text.push('\n');
13309            current_line.truncate(line_prefix.len());
13310            current_line_len = line_prefix_len;
13311            if !is_whitespace {
13312                current_line.push_str(token);
13313                current_line_len += grapheme_len;
13314            }
13315        } else if !is_whitespace {
13316            current_line.push_str(token);
13317            current_line_len += grapheme_len;
13318        } else if current_line_len != line_prefix_len {
13319            current_line.push(' ');
13320            current_line_len += 1;
13321        }
13322    }
13323
13324    if !current_line.is_empty() {
13325        wrapped_text.push_str(&current_line);
13326    }
13327    wrapped_text
13328}
13329
13330#[test]
13331fn test_wrap_with_prefix() {
13332    assert_eq!(
13333        wrap_with_prefix(
13334            "# ".to_string(),
13335            "abcdefg".to_string(),
13336            4,
13337            NonZeroU32::new(4).unwrap()
13338        ),
13339        "# abcdefg"
13340    );
13341    assert_eq!(
13342        wrap_with_prefix(
13343            "".to_string(),
13344            "\thello world".to_string(),
13345            8,
13346            NonZeroU32::new(4).unwrap()
13347        ),
13348        "hello\nworld"
13349    );
13350    assert_eq!(
13351        wrap_with_prefix(
13352            "// ".to_string(),
13353            "xx \nyy zz aa bb cc".to_string(),
13354            12,
13355            NonZeroU32::new(4).unwrap()
13356        ),
13357        "// xx yy zz\n// aa bb cc"
13358    );
13359    assert_eq!(
13360        wrap_with_prefix(
13361            String::new(),
13362            "这是什么 \n 钢笔".to_string(),
13363            3,
13364            NonZeroU32::new(4).unwrap()
13365        ),
13366        "这是什\n么 钢\n"
13367    );
13368}
13369
13370fn hunks_for_selections(
13371    multi_buffer_snapshot: &MultiBufferSnapshot,
13372    selections: &[Selection<Anchor>],
13373) -> Vec<MultiBufferDiffHunk> {
13374    let buffer_rows_for_selections = selections.iter().map(|selection| {
13375        let head = selection.head();
13376        let tail = selection.tail();
13377        let start = MultiBufferRow(tail.to_point(multi_buffer_snapshot).row);
13378        let end = MultiBufferRow(head.to_point(multi_buffer_snapshot).row);
13379        if start > end {
13380            end..start
13381        } else {
13382            start..end
13383        }
13384    });
13385
13386    hunks_for_rows(buffer_rows_for_selections, multi_buffer_snapshot)
13387}
13388
13389pub fn hunks_for_rows(
13390    rows: impl Iterator<Item = Range<MultiBufferRow>>,
13391    multi_buffer_snapshot: &MultiBufferSnapshot,
13392) -> Vec<MultiBufferDiffHunk> {
13393    let mut hunks = Vec::new();
13394    let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
13395        HashMap::default();
13396    for selected_multi_buffer_rows in rows {
13397        let query_rows =
13398            selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
13399        for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
13400            // Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
13401            // when the caret is just above or just below the deleted hunk.
13402            let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
13403            let related_to_selection = if allow_adjacent {
13404                hunk.row_range.overlaps(&query_rows)
13405                    || hunk.row_range.start == query_rows.end
13406                    || hunk.row_range.end == query_rows.start
13407            } else {
13408                // `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
13409                // `hunk.row_range` is exclusive (e.g. [2..3] means 2nd row is selected)
13410                hunk.row_range.overlaps(&selected_multi_buffer_rows)
13411                    || selected_multi_buffer_rows.end == hunk.row_range.start
13412            };
13413            if related_to_selection {
13414                if !processed_buffer_rows
13415                    .entry(hunk.buffer_id)
13416                    .or_default()
13417                    .insert(hunk.buffer_range.start..hunk.buffer_range.end)
13418                {
13419                    continue;
13420                }
13421                hunks.push(hunk);
13422            }
13423        }
13424    }
13425
13426    hunks
13427}
13428
13429pub trait CollaborationHub {
13430    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
13431    fn user_participant_indices<'a>(
13432        &self,
13433        cx: &'a AppContext,
13434    ) -> &'a HashMap<u64, ParticipantIndex>;
13435    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
13436}
13437
13438impl CollaborationHub for Model<Project> {
13439    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
13440        self.read(cx).collaborators()
13441    }
13442
13443    fn user_participant_indices<'a>(
13444        &self,
13445        cx: &'a AppContext,
13446    ) -> &'a HashMap<u64, ParticipantIndex> {
13447        self.read(cx).user_store().read(cx).participant_indices()
13448    }
13449
13450    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
13451        let this = self.read(cx);
13452        let user_ids = this.collaborators().values().map(|c| c.user_id);
13453        this.user_store().read_with(cx, |user_store, cx| {
13454            user_store.participant_names(user_ids, cx)
13455        })
13456    }
13457}
13458
13459pub trait SemanticsProvider {
13460    fn hover(
13461        &self,
13462        buffer: &Model<Buffer>,
13463        position: text::Anchor,
13464        cx: &mut AppContext,
13465    ) -> Option<Task<Vec<project::Hover>>>;
13466
13467    fn inlay_hints(
13468        &self,
13469        buffer_handle: Model<Buffer>,
13470        range: Range<text::Anchor>,
13471        cx: &mut AppContext,
13472    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
13473
13474    fn resolve_inlay_hint(
13475        &self,
13476        hint: InlayHint,
13477        buffer_handle: Model<Buffer>,
13478        server_id: LanguageServerId,
13479        cx: &mut AppContext,
13480    ) -> Option<Task<anyhow::Result<InlayHint>>>;
13481
13482    fn supports_inlay_hints(&self, buffer: &Model<Buffer>, cx: &AppContext) -> bool;
13483
13484    fn document_highlights(
13485        &self,
13486        buffer: &Model<Buffer>,
13487        position: text::Anchor,
13488        cx: &mut AppContext,
13489    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
13490
13491    fn definitions(
13492        &self,
13493        buffer: &Model<Buffer>,
13494        position: text::Anchor,
13495        kind: GotoDefinitionKind,
13496        cx: &mut AppContext,
13497    ) -> Option<Task<Result<Vec<LocationLink>>>>;
13498
13499    fn range_for_rename(
13500        &self,
13501        buffer: &Model<Buffer>,
13502        position: text::Anchor,
13503        cx: &mut AppContext,
13504    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
13505
13506    fn perform_rename(
13507        &self,
13508        buffer: &Model<Buffer>,
13509        position: text::Anchor,
13510        new_name: String,
13511        cx: &mut AppContext,
13512    ) -> Option<Task<Result<ProjectTransaction>>>;
13513}
13514
13515pub trait CompletionProvider {
13516    fn completions(
13517        &self,
13518        buffer: &Model<Buffer>,
13519        buffer_position: text::Anchor,
13520        trigger: CompletionContext,
13521        cx: &mut ViewContext<Editor>,
13522    ) -> Task<Result<Vec<Completion>>>;
13523
13524    fn resolve_completions(
13525        &self,
13526        buffer: Model<Buffer>,
13527        completion_indices: Vec<usize>,
13528        completions: Arc<RwLock<Box<[Completion]>>>,
13529        cx: &mut ViewContext<Editor>,
13530    ) -> Task<Result<bool>>;
13531
13532    fn apply_additional_edits_for_completion(
13533        &self,
13534        buffer: Model<Buffer>,
13535        completion: Completion,
13536        push_to_history: bool,
13537        cx: &mut ViewContext<Editor>,
13538    ) -> Task<Result<Option<language::Transaction>>>;
13539
13540    fn is_completion_trigger(
13541        &self,
13542        buffer: &Model<Buffer>,
13543        position: language::Anchor,
13544        text: &str,
13545        trigger_in_words: bool,
13546        cx: &mut ViewContext<Editor>,
13547    ) -> bool;
13548
13549    fn sort_completions(&self) -> bool {
13550        true
13551    }
13552}
13553
13554pub trait CodeActionProvider {
13555    fn code_actions(
13556        &self,
13557        buffer: &Model<Buffer>,
13558        range: Range<text::Anchor>,
13559        cx: &mut WindowContext,
13560    ) -> Task<Result<Vec<CodeAction>>>;
13561
13562    fn apply_code_action(
13563        &self,
13564        buffer_handle: Model<Buffer>,
13565        action: CodeAction,
13566        excerpt_id: ExcerptId,
13567        push_to_history: bool,
13568        cx: &mut WindowContext,
13569    ) -> Task<Result<ProjectTransaction>>;
13570}
13571
13572impl CodeActionProvider for Model<Project> {
13573    fn code_actions(
13574        &self,
13575        buffer: &Model<Buffer>,
13576        range: Range<text::Anchor>,
13577        cx: &mut WindowContext,
13578    ) -> Task<Result<Vec<CodeAction>>> {
13579        self.update(cx, |project, cx| project.code_actions(buffer, range, cx))
13580    }
13581
13582    fn apply_code_action(
13583        &self,
13584        buffer_handle: Model<Buffer>,
13585        action: CodeAction,
13586        _excerpt_id: ExcerptId,
13587        push_to_history: bool,
13588        cx: &mut WindowContext,
13589    ) -> Task<Result<ProjectTransaction>> {
13590        self.update(cx, |project, cx| {
13591            project.apply_code_action(buffer_handle, action, push_to_history, cx)
13592        })
13593    }
13594}
13595
13596fn snippet_completions(
13597    project: &Project,
13598    buffer: &Model<Buffer>,
13599    buffer_position: text::Anchor,
13600    cx: &mut AppContext,
13601) -> Vec<Completion> {
13602    let language = buffer.read(cx).language_at(buffer_position);
13603    let language_name = language.as_ref().map(|language| language.lsp_id());
13604    let snippet_store = project.snippets().read(cx);
13605    let snippets = snippet_store.snippets_for(language_name, cx);
13606
13607    if snippets.is_empty() {
13608        return vec![];
13609    }
13610    let snapshot = buffer.read(cx).text_snapshot();
13611    let chars = snapshot.reversed_chars_for_range(text::Anchor::MIN..buffer_position);
13612
13613    let scope = language.map(|language| language.default_scope());
13614    let classifier = CharClassifier::new(scope).for_completion(true);
13615    let mut last_word = chars
13616        .take_while(|c| classifier.is_word(*c))
13617        .collect::<String>();
13618    last_word = last_word.chars().rev().collect();
13619    let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
13620    let to_lsp = |point: &text::Anchor| {
13621        let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
13622        point_to_lsp(end)
13623    };
13624    let lsp_end = to_lsp(&buffer_position);
13625    snippets
13626        .into_iter()
13627        .filter_map(|snippet| {
13628            let matching_prefix = snippet
13629                .prefix
13630                .iter()
13631                .find(|prefix| prefix.starts_with(&last_word))?;
13632            let start = as_offset - last_word.len();
13633            let start = snapshot.anchor_before(start);
13634            let range = start..buffer_position;
13635            let lsp_start = to_lsp(&start);
13636            let lsp_range = lsp::Range {
13637                start: lsp_start,
13638                end: lsp_end,
13639            };
13640            Some(Completion {
13641                old_range: range,
13642                new_text: snippet.body.clone(),
13643                label: CodeLabel {
13644                    text: matching_prefix.clone(),
13645                    runs: vec![],
13646                    filter_range: 0..matching_prefix.len(),
13647                },
13648                server_id: LanguageServerId(usize::MAX),
13649                documentation: snippet.description.clone().map(Documentation::SingleLine),
13650                lsp_completion: lsp::CompletionItem {
13651                    label: snippet.prefix.first().unwrap().clone(),
13652                    kind: Some(CompletionItemKind::SNIPPET),
13653                    label_details: snippet.description.as_ref().map(|description| {
13654                        lsp::CompletionItemLabelDetails {
13655                            detail: Some(description.clone()),
13656                            description: None,
13657                        }
13658                    }),
13659                    insert_text_format: Some(InsertTextFormat::SNIPPET),
13660                    text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
13661                        lsp::InsertReplaceEdit {
13662                            new_text: snippet.body.clone(),
13663                            insert: lsp_range,
13664                            replace: lsp_range,
13665                        },
13666                    )),
13667                    filter_text: Some(snippet.body.clone()),
13668                    sort_text: Some(char::MAX.to_string()),
13669                    ..Default::default()
13670                },
13671                confirm: None,
13672            })
13673        })
13674        .collect()
13675}
13676
13677impl CompletionProvider for Model<Project> {
13678    fn completions(
13679        &self,
13680        buffer: &Model<Buffer>,
13681        buffer_position: text::Anchor,
13682        options: CompletionContext,
13683        cx: &mut ViewContext<Editor>,
13684    ) -> Task<Result<Vec<Completion>>> {
13685        self.update(cx, |project, cx| {
13686            let snippets = snippet_completions(project, buffer, buffer_position, cx);
13687            let project_completions = project.completions(buffer, buffer_position, options, cx);
13688            cx.background_executor().spawn(async move {
13689                let mut completions = project_completions.await?;
13690                //let snippets = snippets.into_iter().;
13691                completions.extend(snippets);
13692                Ok(completions)
13693            })
13694        })
13695    }
13696
13697    fn resolve_completions(
13698        &self,
13699        buffer: Model<Buffer>,
13700        completion_indices: Vec<usize>,
13701        completions: Arc<RwLock<Box<[Completion]>>>,
13702        cx: &mut ViewContext<Editor>,
13703    ) -> Task<Result<bool>> {
13704        self.update(cx, |project, cx| {
13705            project.resolve_completions(buffer, completion_indices, completions, cx)
13706        })
13707    }
13708
13709    fn apply_additional_edits_for_completion(
13710        &self,
13711        buffer: Model<Buffer>,
13712        completion: Completion,
13713        push_to_history: bool,
13714        cx: &mut ViewContext<Editor>,
13715    ) -> Task<Result<Option<language::Transaction>>> {
13716        self.update(cx, |project, cx| {
13717            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
13718        })
13719    }
13720
13721    fn is_completion_trigger(
13722        &self,
13723        buffer: &Model<Buffer>,
13724        position: language::Anchor,
13725        text: &str,
13726        trigger_in_words: bool,
13727        cx: &mut ViewContext<Editor>,
13728    ) -> bool {
13729        if !EditorSettings::get_global(cx).show_completions_on_input {
13730            return false;
13731        }
13732
13733        let mut chars = text.chars();
13734        let char = if let Some(char) = chars.next() {
13735            char
13736        } else {
13737            return false;
13738        };
13739        if chars.next().is_some() {
13740            return false;
13741        }
13742
13743        let buffer = buffer.read(cx);
13744        let classifier = buffer
13745            .snapshot()
13746            .char_classifier_at(position)
13747            .for_completion(true);
13748        if trigger_in_words && classifier.is_word(char) {
13749            return true;
13750        }
13751
13752        buffer.completion_triggers().contains(text)
13753    }
13754}
13755
13756impl SemanticsProvider for Model<Project> {
13757    fn hover(
13758        &self,
13759        buffer: &Model<Buffer>,
13760        position: text::Anchor,
13761        cx: &mut AppContext,
13762    ) -> Option<Task<Vec<project::Hover>>> {
13763        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
13764    }
13765
13766    fn document_highlights(
13767        &self,
13768        buffer: &Model<Buffer>,
13769        position: text::Anchor,
13770        cx: &mut AppContext,
13771    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
13772        Some(self.update(cx, |project, cx| {
13773            project.document_highlights(buffer, position, cx)
13774        }))
13775    }
13776
13777    fn definitions(
13778        &self,
13779        buffer: &Model<Buffer>,
13780        position: text::Anchor,
13781        kind: GotoDefinitionKind,
13782        cx: &mut AppContext,
13783    ) -> Option<Task<Result<Vec<LocationLink>>>> {
13784        Some(self.update(cx, |project, cx| match kind {
13785            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
13786            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
13787            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
13788            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
13789        }))
13790    }
13791
13792    fn supports_inlay_hints(&self, buffer: &Model<Buffer>, cx: &AppContext) -> bool {
13793        // TODO: make this work for remote projects
13794        self.read(cx)
13795            .language_servers_for_buffer(buffer.read(cx), cx)
13796            .any(
13797                |(_, server)| match server.capabilities().inlay_hint_provider {
13798                    Some(lsp::OneOf::Left(enabled)) => enabled,
13799                    Some(lsp::OneOf::Right(_)) => true,
13800                    None => false,
13801                },
13802            )
13803    }
13804
13805    fn inlay_hints(
13806        &self,
13807        buffer_handle: Model<Buffer>,
13808        range: Range<text::Anchor>,
13809        cx: &mut AppContext,
13810    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
13811        Some(self.update(cx, |project, cx| {
13812            project.inlay_hints(buffer_handle, range, cx)
13813        }))
13814    }
13815
13816    fn resolve_inlay_hint(
13817        &self,
13818        hint: InlayHint,
13819        buffer_handle: Model<Buffer>,
13820        server_id: LanguageServerId,
13821        cx: &mut AppContext,
13822    ) -> Option<Task<anyhow::Result<InlayHint>>> {
13823        Some(self.update(cx, |project, cx| {
13824            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
13825        }))
13826    }
13827
13828    fn range_for_rename(
13829        &self,
13830        buffer: &Model<Buffer>,
13831        position: text::Anchor,
13832        cx: &mut AppContext,
13833    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
13834        Some(self.update(cx, |project, cx| {
13835            project.prepare_rename(buffer.clone(), position, cx)
13836        }))
13837    }
13838
13839    fn perform_rename(
13840        &self,
13841        buffer: &Model<Buffer>,
13842        position: text::Anchor,
13843        new_name: String,
13844        cx: &mut AppContext,
13845    ) -> Option<Task<Result<ProjectTransaction>>> {
13846        Some(self.update(cx, |project, cx| {
13847            project.perform_rename(buffer.clone(), position, new_name, cx)
13848        }))
13849    }
13850}
13851
13852fn inlay_hint_settings(
13853    location: Anchor,
13854    snapshot: &MultiBufferSnapshot,
13855    cx: &mut ViewContext<'_, Editor>,
13856) -> InlayHintSettings {
13857    let file = snapshot.file_at(location);
13858    let language = snapshot.language_at(location).map(|l| l.name());
13859    language_settings(language, file, cx).inlay_hints
13860}
13861
13862fn consume_contiguous_rows(
13863    contiguous_row_selections: &mut Vec<Selection<Point>>,
13864    selection: &Selection<Point>,
13865    display_map: &DisplaySnapshot,
13866    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
13867) -> (MultiBufferRow, MultiBufferRow) {
13868    contiguous_row_selections.push(selection.clone());
13869    let start_row = MultiBufferRow(selection.start.row);
13870    let mut end_row = ending_row(selection, display_map);
13871
13872    while let Some(next_selection) = selections.peek() {
13873        if next_selection.start.row <= end_row.0 {
13874            end_row = ending_row(next_selection, display_map);
13875            contiguous_row_selections.push(selections.next().unwrap().clone());
13876        } else {
13877            break;
13878        }
13879    }
13880    (start_row, end_row)
13881}
13882
13883fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
13884    if next_selection.end.column > 0 || next_selection.is_empty() {
13885        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
13886    } else {
13887        MultiBufferRow(next_selection.end.row)
13888    }
13889}
13890
13891impl EditorSnapshot {
13892    pub fn remote_selections_in_range<'a>(
13893        &'a self,
13894        range: &'a Range<Anchor>,
13895        collaboration_hub: &dyn CollaborationHub,
13896        cx: &'a AppContext,
13897    ) -> impl 'a + Iterator<Item = RemoteSelection> {
13898        let participant_names = collaboration_hub.user_names(cx);
13899        let participant_indices = collaboration_hub.user_participant_indices(cx);
13900        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
13901        let collaborators_by_replica_id = collaborators_by_peer_id
13902            .iter()
13903            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
13904            .collect::<HashMap<_, _>>();
13905        self.buffer_snapshot
13906            .selections_in_range(range, false)
13907            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
13908                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
13909                let participant_index = participant_indices.get(&collaborator.user_id).copied();
13910                let user_name = participant_names.get(&collaborator.user_id).cloned();
13911                Some(RemoteSelection {
13912                    replica_id,
13913                    selection,
13914                    cursor_shape,
13915                    line_mode,
13916                    participant_index,
13917                    peer_id: collaborator.peer_id,
13918                    user_name,
13919                })
13920            })
13921    }
13922
13923    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
13924        self.display_snapshot.buffer_snapshot.language_at(position)
13925    }
13926
13927    pub fn is_focused(&self) -> bool {
13928        self.is_focused
13929    }
13930
13931    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
13932        self.placeholder_text.as_ref()
13933    }
13934
13935    pub fn scroll_position(&self) -> gpui::Point<f32> {
13936        self.scroll_anchor.scroll_position(&self.display_snapshot)
13937    }
13938
13939    fn gutter_dimensions(
13940        &self,
13941        font_id: FontId,
13942        font_size: Pixels,
13943        em_width: Pixels,
13944        em_advance: Pixels,
13945        max_line_number_width: Pixels,
13946        cx: &AppContext,
13947    ) -> GutterDimensions {
13948        if !self.show_gutter {
13949            return GutterDimensions::default();
13950        }
13951        let descent = cx.text_system().descent(font_id, font_size);
13952
13953        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
13954            matches!(
13955                ProjectSettings::get_global(cx).git.git_gutter,
13956                Some(GitGutterSetting::TrackedFiles)
13957            )
13958        });
13959        let gutter_settings = EditorSettings::get_global(cx).gutter;
13960        let show_line_numbers = self
13961            .show_line_numbers
13962            .unwrap_or(gutter_settings.line_numbers);
13963        let line_gutter_width = if show_line_numbers {
13964            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
13965            let min_width_for_number_on_gutter = em_advance * 4.0;
13966            max_line_number_width.max(min_width_for_number_on_gutter)
13967        } else {
13968            0.0.into()
13969        };
13970
13971        let show_code_actions = self
13972            .show_code_actions
13973            .unwrap_or(gutter_settings.code_actions);
13974
13975        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
13976
13977        let git_blame_entries_width =
13978            self.git_blame_gutter_max_author_length
13979                .map(|max_author_length| {
13980                    // Length of the author name, but also space for the commit hash,
13981                    // the spacing and the timestamp.
13982                    let max_char_count = max_author_length
13983                        .min(GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED)
13984                        + 7 // length of commit sha
13985                        + 14 // length of max relative timestamp ("60 minutes ago")
13986                        + 4; // gaps and margins
13987
13988                    em_advance * max_char_count
13989                });
13990
13991        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
13992        left_padding += if show_code_actions || show_runnables {
13993            em_width * 3.0
13994        } else if show_git_gutter && show_line_numbers {
13995            em_width * 2.0
13996        } else if show_git_gutter || show_line_numbers {
13997            em_width
13998        } else {
13999            px(0.)
14000        };
14001
14002        let right_padding = if gutter_settings.folds && show_line_numbers {
14003            em_width * 4.0
14004        } else if gutter_settings.folds {
14005            em_width * 3.0
14006        } else if show_line_numbers {
14007            em_width
14008        } else {
14009            px(0.)
14010        };
14011
14012        GutterDimensions {
14013            left_padding,
14014            right_padding,
14015            width: line_gutter_width + left_padding + right_padding,
14016            margin: -descent,
14017            git_blame_entries_width,
14018        }
14019    }
14020
14021    pub fn render_fold_toggle(
14022        &self,
14023        buffer_row: MultiBufferRow,
14024        row_contains_cursor: bool,
14025        editor: View<Editor>,
14026        cx: &mut WindowContext,
14027    ) -> Option<AnyElement> {
14028        let folded = self.is_line_folded(buffer_row);
14029
14030        if let Some(crease) = self
14031            .crease_snapshot
14032            .query_row(buffer_row, &self.buffer_snapshot)
14033        {
14034            let toggle_callback = Arc::new(move |folded, cx: &mut WindowContext| {
14035                if folded {
14036                    editor.update(cx, |editor, cx| {
14037                        editor.fold_at(&crate::FoldAt { buffer_row }, cx)
14038                    });
14039                } else {
14040                    editor.update(cx, |editor, cx| {
14041                        editor.unfold_at(&crate::UnfoldAt { buffer_row }, cx)
14042                    });
14043                }
14044            });
14045
14046            Some((crease.render_toggle)(
14047                buffer_row,
14048                folded,
14049                toggle_callback,
14050                cx,
14051            ))
14052        } else if folded
14053            || (self.starts_indent(buffer_row) && (row_contains_cursor || self.gutter_hovered))
14054        {
14055            Some(
14056                Disclosure::new(("indent-fold-indicator", buffer_row.0), !folded)
14057                    .selected(folded)
14058                    .on_click(cx.listener_for(&editor, move |this, _e, cx| {
14059                        if folded {
14060                            this.unfold_at(&UnfoldAt { buffer_row }, cx);
14061                        } else {
14062                            this.fold_at(&FoldAt { buffer_row }, cx);
14063                        }
14064                    }))
14065                    .into_any_element(),
14066            )
14067        } else {
14068            None
14069        }
14070    }
14071
14072    pub fn render_crease_trailer(
14073        &self,
14074        buffer_row: MultiBufferRow,
14075        cx: &mut WindowContext,
14076    ) -> Option<AnyElement> {
14077        let folded = self.is_line_folded(buffer_row);
14078        let crease = self
14079            .crease_snapshot
14080            .query_row(buffer_row, &self.buffer_snapshot)?;
14081        Some((crease.render_trailer)(buffer_row, folded, cx))
14082    }
14083}
14084
14085impl Deref for EditorSnapshot {
14086    type Target = DisplaySnapshot;
14087
14088    fn deref(&self) -> &Self::Target {
14089        &self.display_snapshot
14090    }
14091}
14092
14093#[derive(Clone, Debug, PartialEq, Eq)]
14094pub enum EditorEvent {
14095    InputIgnored {
14096        text: Arc<str>,
14097    },
14098    InputHandled {
14099        utf16_range_to_replace: Option<Range<isize>>,
14100        text: Arc<str>,
14101    },
14102    ExcerptsAdded {
14103        buffer: Model<Buffer>,
14104        predecessor: ExcerptId,
14105        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
14106    },
14107    ExcerptsRemoved {
14108        ids: Vec<ExcerptId>,
14109    },
14110    ExcerptsEdited {
14111        ids: Vec<ExcerptId>,
14112    },
14113    ExcerptsExpanded {
14114        ids: Vec<ExcerptId>,
14115    },
14116    BufferEdited,
14117    Edited {
14118        transaction_id: clock::Lamport,
14119    },
14120    Reparsed(BufferId),
14121    Focused,
14122    FocusedIn,
14123    Blurred,
14124    DirtyChanged,
14125    Saved,
14126    TitleChanged,
14127    DiffBaseChanged,
14128    SelectionsChanged {
14129        local: bool,
14130    },
14131    ScrollPositionChanged {
14132        local: bool,
14133        autoscroll: bool,
14134    },
14135    Closed,
14136    TransactionUndone {
14137        transaction_id: clock::Lamport,
14138    },
14139    TransactionBegun {
14140        transaction_id: clock::Lamport,
14141    },
14142    Reloaded,
14143    CursorShapeChanged,
14144}
14145
14146impl EventEmitter<EditorEvent> for Editor {}
14147
14148impl FocusableView for Editor {
14149    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
14150        self.focus_handle.clone()
14151    }
14152}
14153
14154impl Render for Editor {
14155    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
14156        let settings = ThemeSettings::get_global(cx);
14157
14158        let mut text_style = match self.mode {
14159            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
14160                color: cx.theme().colors().editor_foreground,
14161                font_family: settings.ui_font.family.clone(),
14162                font_features: settings.ui_font.features.clone(),
14163                font_fallbacks: settings.ui_font.fallbacks.clone(),
14164                font_size: rems(0.875).into(),
14165                font_weight: settings.ui_font.weight,
14166                line_height: relative(settings.buffer_line_height.value()),
14167                ..Default::default()
14168            },
14169            EditorMode::Full => TextStyle {
14170                color: cx.theme().colors().editor_foreground,
14171                font_family: settings.buffer_font.family.clone(),
14172                font_features: settings.buffer_font.features.clone(),
14173                font_fallbacks: settings.buffer_font.fallbacks.clone(),
14174                font_size: settings.buffer_font_size(cx).into(),
14175                font_weight: settings.buffer_font.weight,
14176                line_height: relative(settings.buffer_line_height.value()),
14177                ..Default::default()
14178            },
14179        };
14180        if let Some(text_style_refinement) = &self.text_style_refinement {
14181            text_style.refine(text_style_refinement)
14182        }
14183
14184        let background = match self.mode {
14185            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
14186            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
14187            EditorMode::Full => cx.theme().colors().editor_background,
14188        };
14189
14190        EditorElement::new(
14191            cx.view(),
14192            EditorStyle {
14193                background,
14194                local_player: cx.theme().players().local(),
14195                text: text_style,
14196                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
14197                syntax: cx.theme().syntax().clone(),
14198                status: cx.theme().status().clone(),
14199                inlay_hints_style: make_inlay_hints_style(cx),
14200                suggestions_style: HighlightStyle {
14201                    color: Some(cx.theme().status().predictive),
14202                    ..HighlightStyle::default()
14203                },
14204                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
14205            },
14206        )
14207    }
14208}
14209
14210impl ViewInputHandler for Editor {
14211    fn text_for_range(
14212        &mut self,
14213        range_utf16: Range<usize>,
14214        cx: &mut ViewContext<Self>,
14215    ) -> Option<String> {
14216        Some(
14217            self.buffer
14218                .read(cx)
14219                .read(cx)
14220                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
14221                .collect(),
14222        )
14223    }
14224
14225    fn selected_text_range(
14226        &mut self,
14227        ignore_disabled_input: bool,
14228        cx: &mut ViewContext<Self>,
14229    ) -> Option<UTF16Selection> {
14230        // Prevent the IME menu from appearing when holding down an alphabetic key
14231        // while input is disabled.
14232        if !ignore_disabled_input && !self.input_enabled {
14233            return None;
14234        }
14235
14236        let selection = self.selections.newest::<OffsetUtf16>(cx);
14237        let range = selection.range();
14238
14239        Some(UTF16Selection {
14240            range: range.start.0..range.end.0,
14241            reversed: selection.reversed,
14242        })
14243    }
14244
14245    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
14246        let snapshot = self.buffer.read(cx).read(cx);
14247        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
14248        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
14249    }
14250
14251    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
14252        self.clear_highlights::<InputComposition>(cx);
14253        self.ime_transaction.take();
14254    }
14255
14256    fn replace_text_in_range(
14257        &mut self,
14258        range_utf16: Option<Range<usize>>,
14259        text: &str,
14260        cx: &mut ViewContext<Self>,
14261    ) {
14262        if !self.input_enabled {
14263            cx.emit(EditorEvent::InputIgnored { text: text.into() });
14264            return;
14265        }
14266
14267        self.transact(cx, |this, cx| {
14268            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
14269                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
14270                Some(this.selection_replacement_ranges(range_utf16, cx))
14271            } else {
14272                this.marked_text_ranges(cx)
14273            };
14274
14275            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
14276                let newest_selection_id = this.selections.newest_anchor().id;
14277                this.selections
14278                    .all::<OffsetUtf16>(cx)
14279                    .iter()
14280                    .zip(ranges_to_replace.iter())
14281                    .find_map(|(selection, range)| {
14282                        if selection.id == newest_selection_id {
14283                            Some(
14284                                (range.start.0 as isize - selection.head().0 as isize)
14285                                    ..(range.end.0 as isize - selection.head().0 as isize),
14286                            )
14287                        } else {
14288                            None
14289                        }
14290                    })
14291            });
14292
14293            cx.emit(EditorEvent::InputHandled {
14294                utf16_range_to_replace: range_to_replace,
14295                text: text.into(),
14296            });
14297
14298            if let Some(new_selected_ranges) = new_selected_ranges {
14299                this.change_selections(None, cx, |selections| {
14300                    selections.select_ranges(new_selected_ranges)
14301                });
14302                this.backspace(&Default::default(), cx);
14303            }
14304
14305            this.handle_input(text, cx);
14306        });
14307
14308        if let Some(transaction) = self.ime_transaction {
14309            self.buffer.update(cx, |buffer, cx| {
14310                buffer.group_until_transaction(transaction, cx);
14311            });
14312        }
14313
14314        self.unmark_text(cx);
14315    }
14316
14317    fn replace_and_mark_text_in_range(
14318        &mut self,
14319        range_utf16: Option<Range<usize>>,
14320        text: &str,
14321        new_selected_range_utf16: Option<Range<usize>>,
14322        cx: &mut ViewContext<Self>,
14323    ) {
14324        if !self.input_enabled {
14325            return;
14326        }
14327
14328        let transaction = self.transact(cx, |this, cx| {
14329            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
14330                let snapshot = this.buffer.read(cx).read(cx);
14331                if let Some(relative_range_utf16) = range_utf16.as_ref() {
14332                    for marked_range in &mut marked_ranges {
14333                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
14334                        marked_range.start.0 += relative_range_utf16.start;
14335                        marked_range.start =
14336                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
14337                        marked_range.end =
14338                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
14339                    }
14340                }
14341                Some(marked_ranges)
14342            } else if let Some(range_utf16) = range_utf16 {
14343                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
14344                Some(this.selection_replacement_ranges(range_utf16, cx))
14345            } else {
14346                None
14347            };
14348
14349            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
14350                let newest_selection_id = this.selections.newest_anchor().id;
14351                this.selections
14352                    .all::<OffsetUtf16>(cx)
14353                    .iter()
14354                    .zip(ranges_to_replace.iter())
14355                    .find_map(|(selection, range)| {
14356                        if selection.id == newest_selection_id {
14357                            Some(
14358                                (range.start.0 as isize - selection.head().0 as isize)
14359                                    ..(range.end.0 as isize - selection.head().0 as isize),
14360                            )
14361                        } else {
14362                            None
14363                        }
14364                    })
14365            });
14366
14367            cx.emit(EditorEvent::InputHandled {
14368                utf16_range_to_replace: range_to_replace,
14369                text: text.into(),
14370            });
14371
14372            if let Some(ranges) = ranges_to_replace {
14373                this.change_selections(None, cx, |s| s.select_ranges(ranges));
14374            }
14375
14376            let marked_ranges = {
14377                let snapshot = this.buffer.read(cx).read(cx);
14378                this.selections
14379                    .disjoint_anchors()
14380                    .iter()
14381                    .map(|selection| {
14382                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
14383                    })
14384                    .collect::<Vec<_>>()
14385            };
14386
14387            if text.is_empty() {
14388                this.unmark_text(cx);
14389            } else {
14390                this.highlight_text::<InputComposition>(
14391                    marked_ranges.clone(),
14392                    HighlightStyle {
14393                        underline: Some(UnderlineStyle {
14394                            thickness: px(1.),
14395                            color: None,
14396                            wavy: false,
14397                        }),
14398                        ..Default::default()
14399                    },
14400                    cx,
14401                );
14402            }
14403
14404            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
14405            let use_autoclose = this.use_autoclose;
14406            let use_auto_surround = this.use_auto_surround;
14407            this.set_use_autoclose(false);
14408            this.set_use_auto_surround(false);
14409            this.handle_input(text, cx);
14410            this.set_use_autoclose(use_autoclose);
14411            this.set_use_auto_surround(use_auto_surround);
14412
14413            if let Some(new_selected_range) = new_selected_range_utf16 {
14414                let snapshot = this.buffer.read(cx).read(cx);
14415                let new_selected_ranges = marked_ranges
14416                    .into_iter()
14417                    .map(|marked_range| {
14418                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
14419                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
14420                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
14421                        snapshot.clip_offset_utf16(new_start, Bias::Left)
14422                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
14423                    })
14424                    .collect::<Vec<_>>();
14425
14426                drop(snapshot);
14427                this.change_selections(None, cx, |selections| {
14428                    selections.select_ranges(new_selected_ranges)
14429                });
14430            }
14431        });
14432
14433        self.ime_transaction = self.ime_transaction.or(transaction);
14434        if let Some(transaction) = self.ime_transaction {
14435            self.buffer.update(cx, |buffer, cx| {
14436                buffer.group_until_transaction(transaction, cx);
14437            });
14438        }
14439
14440        if self.text_highlights::<InputComposition>(cx).is_none() {
14441            self.ime_transaction.take();
14442        }
14443    }
14444
14445    fn bounds_for_range(
14446        &mut self,
14447        range_utf16: Range<usize>,
14448        element_bounds: gpui::Bounds<Pixels>,
14449        cx: &mut ViewContext<Self>,
14450    ) -> Option<gpui::Bounds<Pixels>> {
14451        let text_layout_details = self.text_layout_details(cx);
14452        let style = &text_layout_details.editor_style;
14453        let font_id = cx.text_system().resolve_font(&style.text.font());
14454        let font_size = style.text.font_size.to_pixels(cx.rem_size());
14455        let line_height = style.text.line_height_in_pixels(cx.rem_size());
14456
14457        let em_width = cx
14458            .text_system()
14459            .typographic_bounds(font_id, font_size, 'm')
14460            .unwrap()
14461            .size
14462            .width;
14463
14464        let snapshot = self.snapshot(cx);
14465        let scroll_position = snapshot.scroll_position();
14466        let scroll_left = scroll_position.x * em_width;
14467
14468        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
14469        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
14470            + self.gutter_dimensions.width;
14471        let y = line_height * (start.row().as_f32() - scroll_position.y);
14472
14473        Some(Bounds {
14474            origin: element_bounds.origin + point(x, y),
14475            size: size(em_width, line_height),
14476        })
14477    }
14478}
14479
14480trait SelectionExt {
14481    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
14482    fn spanned_rows(
14483        &self,
14484        include_end_if_at_line_start: bool,
14485        map: &DisplaySnapshot,
14486    ) -> Range<MultiBufferRow>;
14487}
14488
14489impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
14490    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
14491        let start = self
14492            .start
14493            .to_point(&map.buffer_snapshot)
14494            .to_display_point(map);
14495        let end = self
14496            .end
14497            .to_point(&map.buffer_snapshot)
14498            .to_display_point(map);
14499        if self.reversed {
14500            end..start
14501        } else {
14502            start..end
14503        }
14504    }
14505
14506    fn spanned_rows(
14507        &self,
14508        include_end_if_at_line_start: bool,
14509        map: &DisplaySnapshot,
14510    ) -> Range<MultiBufferRow> {
14511        let start = self.start.to_point(&map.buffer_snapshot);
14512        let mut end = self.end.to_point(&map.buffer_snapshot);
14513        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
14514            end.row -= 1;
14515        }
14516
14517        let buffer_start = map.prev_line_boundary(start).0;
14518        let buffer_end = map.next_line_boundary(end).0;
14519        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
14520    }
14521}
14522
14523impl<T: InvalidationRegion> InvalidationStack<T> {
14524    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
14525    where
14526        S: Clone + ToOffset,
14527    {
14528        while let Some(region) = self.last() {
14529            let all_selections_inside_invalidation_ranges =
14530                if selections.len() == region.ranges().len() {
14531                    selections
14532                        .iter()
14533                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
14534                        .all(|(selection, invalidation_range)| {
14535                            let head = selection.head().to_offset(buffer);
14536                            invalidation_range.start <= head && invalidation_range.end >= head
14537                        })
14538                } else {
14539                    false
14540                };
14541
14542            if all_selections_inside_invalidation_ranges {
14543                break;
14544            } else {
14545                self.pop();
14546            }
14547        }
14548    }
14549}
14550
14551impl<T> Default for InvalidationStack<T> {
14552    fn default() -> Self {
14553        Self(Default::default())
14554    }
14555}
14556
14557impl<T> Deref for InvalidationStack<T> {
14558    type Target = Vec<T>;
14559
14560    fn deref(&self) -> &Self::Target {
14561        &self.0
14562    }
14563}
14564
14565impl<T> DerefMut for InvalidationStack<T> {
14566    fn deref_mut(&mut self) -> &mut Self::Target {
14567        &mut self.0
14568    }
14569}
14570
14571impl InvalidationRegion for SnippetState {
14572    fn ranges(&self) -> &[Range<Anchor>] {
14573        &self.ranges[self.active_index]
14574    }
14575}
14576
14577pub fn diagnostic_block_renderer(
14578    diagnostic: Diagnostic,
14579    max_message_rows: Option<u8>,
14580    allow_closing: bool,
14581    _is_valid: bool,
14582) -> RenderBlock {
14583    let (text_without_backticks, code_ranges) =
14584        highlight_diagnostic_message(&diagnostic, max_message_rows);
14585
14586    Box::new(move |cx: &mut BlockContext| {
14587        let group_id: SharedString = cx.block_id.to_string().into();
14588
14589        let mut text_style = cx.text_style().clone();
14590        text_style.color = diagnostic_style(diagnostic.severity, cx.theme().status());
14591        let theme_settings = ThemeSettings::get_global(cx);
14592        text_style.font_family = theme_settings.buffer_font.family.clone();
14593        text_style.font_style = theme_settings.buffer_font.style;
14594        text_style.font_features = theme_settings.buffer_font.features.clone();
14595        text_style.font_weight = theme_settings.buffer_font.weight;
14596
14597        let multi_line_diagnostic = diagnostic.message.contains('\n');
14598
14599        let buttons = |diagnostic: &Diagnostic| {
14600            if multi_line_diagnostic {
14601                v_flex()
14602            } else {
14603                h_flex()
14604            }
14605            .when(allow_closing, |div| {
14606                div.children(diagnostic.is_primary.then(|| {
14607                    IconButton::new("close-block", IconName::XCircle)
14608                        .icon_color(Color::Muted)
14609                        .size(ButtonSize::Compact)
14610                        .style(ButtonStyle::Transparent)
14611                        .visible_on_hover(group_id.clone())
14612                        .on_click(move |_click, cx| cx.dispatch_action(Box::new(Cancel)))
14613                        .tooltip(|cx| Tooltip::for_action("Close Diagnostics", &Cancel, cx))
14614                }))
14615            })
14616            .child(
14617                IconButton::new("copy-block", IconName::Copy)
14618                    .icon_color(Color::Muted)
14619                    .size(ButtonSize::Compact)
14620                    .style(ButtonStyle::Transparent)
14621                    .visible_on_hover(group_id.clone())
14622                    .on_click({
14623                        let message = diagnostic.message.clone();
14624                        move |_click, cx| {
14625                            cx.write_to_clipboard(ClipboardItem::new_string(message.clone()))
14626                        }
14627                    })
14628                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
14629            )
14630        };
14631
14632        let icon_size = buttons(&diagnostic)
14633            .into_any_element()
14634            .layout_as_root(AvailableSpace::min_size(), cx);
14635
14636        h_flex()
14637            .id(cx.block_id)
14638            .group(group_id.clone())
14639            .relative()
14640            .size_full()
14641            .pl(cx.gutter_dimensions.width)
14642            .w(cx.max_width - cx.gutter_dimensions.full_width())
14643            .child(
14644                div()
14645                    .flex()
14646                    .w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
14647                    .flex_shrink(),
14648            )
14649            .child(buttons(&diagnostic))
14650            .child(div().flex().flex_shrink_0().child(
14651                StyledText::new(text_without_backticks.clone()).with_highlights(
14652                    &text_style,
14653                    code_ranges.iter().map(|range| {
14654                        (
14655                            range.clone(),
14656                            HighlightStyle {
14657                                font_weight: Some(FontWeight::BOLD),
14658                                ..Default::default()
14659                            },
14660                        )
14661                    }),
14662                ),
14663            ))
14664            .into_any_element()
14665    })
14666}
14667
14668pub fn highlight_diagnostic_message(
14669    diagnostic: &Diagnostic,
14670    mut max_message_rows: Option<u8>,
14671) -> (SharedString, Vec<Range<usize>>) {
14672    let mut text_without_backticks = String::new();
14673    let mut code_ranges = Vec::new();
14674
14675    if let Some(source) = &diagnostic.source {
14676        text_without_backticks.push_str(source);
14677        code_ranges.push(0..source.len());
14678        text_without_backticks.push_str(": ");
14679    }
14680
14681    let mut prev_offset = 0;
14682    let mut in_code_block = false;
14683    let has_row_limit = max_message_rows.is_some();
14684    let mut newline_indices = diagnostic
14685        .message
14686        .match_indices('\n')
14687        .filter(|_| has_row_limit)
14688        .map(|(ix, _)| ix)
14689        .fuse()
14690        .peekable();
14691
14692    for (quote_ix, _) in diagnostic
14693        .message
14694        .match_indices('`')
14695        .chain([(diagnostic.message.len(), "")])
14696    {
14697        let mut first_newline_ix = None;
14698        let mut last_newline_ix = None;
14699        while let Some(newline_ix) = newline_indices.peek() {
14700            if *newline_ix < quote_ix {
14701                if first_newline_ix.is_none() {
14702                    first_newline_ix = Some(*newline_ix);
14703                }
14704                last_newline_ix = Some(*newline_ix);
14705
14706                if let Some(rows_left) = &mut max_message_rows {
14707                    if *rows_left == 0 {
14708                        break;
14709                    } else {
14710                        *rows_left -= 1;
14711                    }
14712                }
14713                let _ = newline_indices.next();
14714            } else {
14715                break;
14716            }
14717        }
14718        let prev_len = text_without_backticks.len();
14719        let new_text = &diagnostic.message[prev_offset..first_newline_ix.unwrap_or(quote_ix)];
14720        text_without_backticks.push_str(new_text);
14721        if in_code_block {
14722            code_ranges.push(prev_len..text_without_backticks.len());
14723        }
14724        prev_offset = last_newline_ix.unwrap_or(quote_ix) + 1;
14725        in_code_block = !in_code_block;
14726        if first_newline_ix.map_or(false, |newline_ix| newline_ix < quote_ix) {
14727            text_without_backticks.push_str("...");
14728            break;
14729        }
14730    }
14731
14732    (text_without_backticks.into(), code_ranges)
14733}
14734
14735fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
14736    match severity {
14737        DiagnosticSeverity::ERROR => colors.error,
14738        DiagnosticSeverity::WARNING => colors.warning,
14739        DiagnosticSeverity::INFORMATION => colors.info,
14740        DiagnosticSeverity::HINT => colors.info,
14741        _ => colors.ignored,
14742    }
14743}
14744
14745pub fn styled_runs_for_code_label<'a>(
14746    label: &'a CodeLabel,
14747    syntax_theme: &'a theme::SyntaxTheme,
14748) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
14749    let fade_out = HighlightStyle {
14750        fade_out: Some(0.35),
14751        ..Default::default()
14752    };
14753
14754    let mut prev_end = label.filter_range.end;
14755    label
14756        .runs
14757        .iter()
14758        .enumerate()
14759        .flat_map(move |(ix, (range, highlight_id))| {
14760            let style = if let Some(style) = highlight_id.style(syntax_theme) {
14761                style
14762            } else {
14763                return Default::default();
14764            };
14765            let mut muted_style = style;
14766            muted_style.highlight(fade_out);
14767
14768            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
14769            if range.start >= label.filter_range.end {
14770                if range.start > prev_end {
14771                    runs.push((prev_end..range.start, fade_out));
14772                }
14773                runs.push((range.clone(), muted_style));
14774            } else if range.end <= label.filter_range.end {
14775                runs.push((range.clone(), style));
14776            } else {
14777                runs.push((range.start..label.filter_range.end, style));
14778                runs.push((label.filter_range.end..range.end, muted_style));
14779            }
14780            prev_end = cmp::max(prev_end, range.end);
14781
14782            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
14783                runs.push((prev_end..label.text.len(), fade_out));
14784            }
14785
14786            runs
14787        })
14788}
14789
14790pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
14791    let mut prev_index = 0;
14792    let mut prev_codepoint: Option<char> = None;
14793    text.char_indices()
14794        .chain([(text.len(), '\0')])
14795        .filter_map(move |(index, codepoint)| {
14796            let prev_codepoint = prev_codepoint.replace(codepoint)?;
14797            let is_boundary = index == text.len()
14798                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
14799                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
14800            if is_boundary {
14801                let chunk = &text[prev_index..index];
14802                prev_index = index;
14803                Some(chunk)
14804            } else {
14805                None
14806            }
14807        })
14808}
14809
14810pub trait RangeToAnchorExt: Sized {
14811    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
14812
14813    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
14814        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
14815        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
14816    }
14817}
14818
14819impl<T: ToOffset> RangeToAnchorExt for Range<T> {
14820    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
14821        let start_offset = self.start.to_offset(snapshot);
14822        let end_offset = self.end.to_offset(snapshot);
14823        if start_offset == end_offset {
14824            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
14825        } else {
14826            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
14827        }
14828    }
14829}
14830
14831pub trait RowExt {
14832    fn as_f32(&self) -> f32;
14833
14834    fn next_row(&self) -> Self;
14835
14836    fn previous_row(&self) -> Self;
14837
14838    fn minus(&self, other: Self) -> u32;
14839}
14840
14841impl RowExt for DisplayRow {
14842    fn as_f32(&self) -> f32 {
14843        self.0 as f32
14844    }
14845
14846    fn next_row(&self) -> Self {
14847        Self(self.0 + 1)
14848    }
14849
14850    fn previous_row(&self) -> Self {
14851        Self(self.0.saturating_sub(1))
14852    }
14853
14854    fn minus(&self, other: Self) -> u32 {
14855        self.0 - other.0
14856    }
14857}
14858
14859impl RowExt for MultiBufferRow {
14860    fn as_f32(&self) -> f32 {
14861        self.0 as f32
14862    }
14863
14864    fn next_row(&self) -> Self {
14865        Self(self.0 + 1)
14866    }
14867
14868    fn previous_row(&self) -> Self {
14869        Self(self.0.saturating_sub(1))
14870    }
14871
14872    fn minus(&self, other: Self) -> u32 {
14873        self.0 - other.0
14874    }
14875}
14876
14877trait RowRangeExt {
14878    type Row;
14879
14880    fn len(&self) -> usize;
14881
14882    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
14883}
14884
14885impl RowRangeExt for Range<MultiBufferRow> {
14886    type Row = MultiBufferRow;
14887
14888    fn len(&self) -> usize {
14889        (self.end.0 - self.start.0) as usize
14890    }
14891
14892    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
14893        (self.start.0..self.end.0).map(MultiBufferRow)
14894    }
14895}
14896
14897impl RowRangeExt for Range<DisplayRow> {
14898    type Row = DisplayRow;
14899
14900    fn len(&self) -> usize {
14901        (self.end.0 - self.start.0) as usize
14902    }
14903
14904    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
14905        (self.start.0..self.end.0).map(DisplayRow)
14906    }
14907}
14908
14909fn hunk_status(hunk: &MultiBufferDiffHunk) -> DiffHunkStatus {
14910    if hunk.diff_base_byte_range.is_empty() {
14911        DiffHunkStatus::Added
14912    } else if hunk.row_range.is_empty() {
14913        DiffHunkStatus::Removed
14914    } else {
14915        DiffHunkStatus::Modified
14916    }
14917}
14918
14919/// If select range has more than one line, we
14920/// just point the cursor to range.start.
14921fn check_multiline_range(buffer: &Buffer, range: Range<usize>) -> Range<usize> {
14922    if buffer.offset_to_point(range.start).row == buffer.offset_to_point(range.end).row {
14923        range
14924    } else {
14925        range.start..range.start
14926    }
14927}
14928
14929const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);