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 behaviour.
   15pub mod actions;
   16mod blame_entry_tooltip;
   17mod blink_manager;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod hunk_diff;
   22mod inlay_hint_cache;
   23
   24mod debounced_delay;
   25mod git;
   26mod highlight_matching_bracket;
   27mod hover_links;
   28mod hover_popover;
   29mod indent_guides;
   30mod inline_completion_provider;
   31pub mod items;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod editor_tests;
   42#[cfg(any(test, feature = "test-support"))]
   43pub mod test;
   44use ::git::diff::{DiffHunk, DiffHunkStatus};
   45use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
   46pub(crate) use actions::*;
   47use aho_corasick::AhoCorasick;
   48use anyhow::{anyhow, Context as _, Result};
   49use blink_manager::BlinkManager;
   50use client::{Collaborator, ParticipantIndex};
   51use clock::ReplicaId;
   52use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
   53use convert_case::{Case, Casing};
   54use debounced_delay::DebouncedDelay;
   55use display_map::*;
   56pub use display_map::{DisplayPoint, FoldPlaceholder};
   57use editor_settings::CurrentLineHighlight;
   58pub use editor_settings::EditorSettings;
   59use element::LineWithInvisibles;
   60pub use element::{
   61    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   62};
   63use futures::FutureExt;
   64use fuzzy::{StringMatch, StringMatchCandidate};
   65use git::blame::GitBlame;
   66use git::diff_hunk_to_display;
   67use gpui::{
   68    div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
   69    AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardItem,
   70    Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,
   71    FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, PaintQuad,
   72    ParentElement, Pixels, Render, SharedString, Size, StrikethroughStyle, Styled, StyledText,
   73    Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View, ViewContext,
   74    ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext,
   75};
   76use highlight_matching_bracket::refresh_matching_bracket_highlights;
   77use hover_popover::{hide_hover, HoverState};
   78use hunk_diff::ExpandedHunks;
   79pub(crate) use hunk_diff::HunkToExpand;
   80use indent_guides::ActiveIndentGuidesState;
   81use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
   82pub use inline_completion_provider::*;
   83pub use items::MAX_TAB_TITLE_LEN;
   84use itertools::Itertools;
   85use language::{
   86    char_kind,
   87    language_settings::{self, all_language_settings, InlayHintSettings},
   88    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
   89    CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
   90    Point, Selection, SelectionGoal, TransactionId,
   91};
   92use language::{BufferRow, Runnable, RunnableRange};
   93use task::{ResolvedTask, TaskTemplate, TaskVariables};
   94
   95use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
   96use lsp::{DiagnosticSeverity, LanguageServerId};
   97use mouse_context_menu::MouseContextMenu;
   98use movement::TextLayoutDetails;
   99pub use multi_buffer::{
  100    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
  101    ToPoint,
  102};
  103use multi_buffer::{MultiBufferPoint, MultiBufferRow, ToOffsetUtf16};
  104use ordered_float::OrderedFloat;
  105use parking_lot::{Mutex, RwLock};
  106use project::project_settings::{GitGutterSetting, ProjectSettings};
  107use project::{
  108    CodeAction, Completion, FormatTrigger, Item, Location, Project, ProjectPath,
  109    ProjectTransaction, TaskSourceKind, WorktreeId,
  110};
  111use rand::prelude::*;
  112use rpc::{proto::*, ErrorExt};
  113use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  114use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
  115use serde::{Deserialize, Serialize};
  116use settings::{Settings, SettingsStore};
  117use smallvec::SmallVec;
  118use snippet::Snippet;
  119use std::ops::Not as _;
  120use std::{
  121    any::TypeId,
  122    borrow::Cow,
  123    cmp::{self, Ordering, Reverse},
  124    mem,
  125    num::NonZeroU32,
  126    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  127    path::Path,
  128    sync::Arc,
  129    time::{Duration, Instant},
  130};
  131pub use sum_tree::Bias;
  132use sum_tree::TreeMap;
  133use text::{BufferId, OffsetUtf16, Rope};
  134use theme::{
  135    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  136    ThemeColors, ThemeSettings,
  137};
  138use ui::{
  139    h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,
  140    Tooltip,
  141};
  142use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  143use workspace::item::{ItemHandle, PreviewTabsSettings};
  144use workspace::notifications::{DetachAndPromptErr, NotificationId};
  145use workspace::{
  146    searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
  147};
  148use workspace::{OpenInTerminal, OpenTerminal, Toast};
  149
  150use crate::hover_links::find_url;
  151
  152pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  153const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  154const MAX_LINE_LEN: usize = 1024;
  155const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  156const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  157pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  158#[doc(hidden)]
  159pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  160#[doc(hidden)]
  161pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  162
  163pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
  164
  165pub fn render_parsed_markdown(
  166    element_id: impl Into<ElementId>,
  167    parsed: &language::ParsedMarkdown,
  168    editor_style: &EditorStyle,
  169    workspace: Option<WeakView<Workspace>>,
  170    cx: &mut WindowContext,
  171) -> InteractiveText {
  172    let code_span_background_color = cx
  173        .theme()
  174        .colors()
  175        .editor_document_highlight_read_background;
  176
  177    let highlights = gpui::combine_highlights(
  178        parsed.highlights.iter().filter_map(|(range, highlight)| {
  179            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
  180            Some((range.clone(), highlight))
  181        }),
  182        parsed
  183            .regions
  184            .iter()
  185            .zip(&parsed.region_ranges)
  186            .filter_map(|(region, range)| {
  187                if region.code {
  188                    Some((
  189                        range.clone(),
  190                        HighlightStyle {
  191                            background_color: Some(code_span_background_color),
  192                            ..Default::default()
  193                        },
  194                    ))
  195                } else {
  196                    None
  197                }
  198            }),
  199    );
  200
  201    let mut links = Vec::new();
  202    let mut link_ranges = Vec::new();
  203    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
  204        if let Some(link) = region.link.clone() {
  205            links.push(link);
  206            link_ranges.push(range.clone());
  207        }
  208    }
  209
  210    InteractiveText::new(
  211        element_id,
  212        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
  213    )
  214    .on_click(link_ranges, move |clicked_range_ix, cx| {
  215        match &links[clicked_range_ix] {
  216            markdown::Link::Web { url } => cx.open_url(url),
  217            markdown::Link::Path { path } => {
  218                if let Some(workspace) = &workspace {
  219                    _ = workspace.update(cx, |workspace, cx| {
  220                        workspace.open_abs_path(path.clone(), false, cx).detach();
  221                    });
  222                }
  223            }
  224        }
  225    })
  226}
  227
  228#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  229pub(crate) enum InlayId {
  230    Suggestion(usize),
  231    Hint(usize),
  232}
  233
  234impl InlayId {
  235    fn id(&self) -> usize {
  236        match self {
  237            Self::Suggestion(id) => *id,
  238            Self::Hint(id) => *id,
  239        }
  240    }
  241}
  242
  243enum DiffRowHighlight {}
  244enum DocumentHighlightRead {}
  245enum DocumentHighlightWrite {}
  246enum InputComposition {}
  247
  248#[derive(Copy, Clone, PartialEq, Eq)]
  249pub enum Direction {
  250    Prev,
  251    Next,
  252}
  253
  254pub fn init_settings(cx: &mut AppContext) {
  255    EditorSettings::register(cx);
  256}
  257
  258pub fn init(cx: &mut AppContext) {
  259    init_settings(cx);
  260
  261    workspace::register_project_item::<Editor>(cx);
  262    workspace::register_followable_item::<Editor>(cx);
  263    workspace::register_deserializable_item::<Editor>(cx);
  264    cx.observe_new_views(
  265        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  266            workspace.register_action(Editor::new_file);
  267            workspace.register_action(Editor::new_file_in_direction);
  268        },
  269    )
  270    .detach();
  271
  272    cx.on_action(move |_: &workspace::NewFile, cx| {
  273        let app_state = workspace::AppState::global(cx);
  274        if let Some(app_state) = app_state.upgrade() {
  275            workspace::open_new(app_state, cx, |workspace, cx| {
  276                Editor::new_file(workspace, &Default::default(), cx)
  277            })
  278            .detach();
  279        }
  280    });
  281    cx.on_action(move |_: &workspace::NewWindow, cx| {
  282        let app_state = workspace::AppState::global(cx);
  283        if let Some(app_state) = app_state.upgrade() {
  284            workspace::open_new(app_state, cx, |workspace, cx| {
  285                Editor::new_file(workspace, &Default::default(), cx)
  286            })
  287            .detach();
  288        }
  289    });
  290}
  291
  292pub struct SearchWithinRange;
  293
  294trait InvalidationRegion {
  295    fn ranges(&self) -> &[Range<Anchor>];
  296}
  297
  298#[derive(Clone, Debug, PartialEq)]
  299pub enum SelectPhase {
  300    Begin {
  301        position: DisplayPoint,
  302        add: bool,
  303        click_count: usize,
  304    },
  305    BeginColumnar {
  306        position: DisplayPoint,
  307        reset: bool,
  308        goal_column: u32,
  309    },
  310    Extend {
  311        position: DisplayPoint,
  312        click_count: usize,
  313    },
  314    Update {
  315        position: DisplayPoint,
  316        goal_column: u32,
  317        scroll_delta: gpui::Point<f32>,
  318    },
  319    End,
  320}
  321
  322#[derive(Clone, Debug)]
  323pub enum SelectMode {
  324    Character,
  325    Word(Range<Anchor>),
  326    Line(Range<Anchor>),
  327    All,
  328}
  329
  330#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  331pub enum EditorMode {
  332    SingleLine,
  333    AutoHeight { max_lines: usize },
  334    Full,
  335}
  336
  337#[derive(Clone, Debug)]
  338pub enum SoftWrap {
  339    None,
  340    PreferLine,
  341    EditorWidth,
  342    Column(u32),
  343}
  344
  345#[derive(Clone)]
  346pub struct EditorStyle {
  347    pub background: Hsla,
  348    pub local_player: PlayerColor,
  349    pub text: TextStyle,
  350    pub scrollbar_width: Pixels,
  351    pub syntax: Arc<SyntaxTheme>,
  352    pub status: StatusColors,
  353    pub inlay_hints_style: HighlightStyle,
  354    pub suggestions_style: HighlightStyle,
  355}
  356
  357impl Default for EditorStyle {
  358    fn default() -> Self {
  359        Self {
  360            background: Hsla::default(),
  361            local_player: PlayerColor::default(),
  362            text: TextStyle::default(),
  363            scrollbar_width: Pixels::default(),
  364            syntax: Default::default(),
  365            // HACK: Status colors don't have a real default.
  366            // We should look into removing the status colors from the editor
  367            // style and retrieve them directly from the theme.
  368            status: StatusColors::dark(),
  369            inlay_hints_style: HighlightStyle::default(),
  370            suggestions_style: HighlightStyle::default(),
  371        }
  372    }
  373}
  374
  375type CompletionId = usize;
  376
  377// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  378// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  379
  380type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  381
  382struct ScrollbarMarkerState {
  383    scrollbar_size: Size<Pixels>,
  384    dirty: bool,
  385    markers: Arc<[PaintQuad]>,
  386    pending_refresh: Option<Task<Result<()>>>,
  387}
  388
  389impl ScrollbarMarkerState {
  390    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  391        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  392    }
  393}
  394
  395impl Default for ScrollbarMarkerState {
  396    fn default() -> Self {
  397        Self {
  398            scrollbar_size: Size::default(),
  399            dirty: false,
  400            markers: Arc::from([]),
  401            pending_refresh: None,
  402        }
  403    }
  404}
  405
  406#[derive(Clone, Debug)]
  407struct RunnableTasks {
  408    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  409    offset: MultiBufferOffset,
  410    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  411    column: u32,
  412    // Values of all named captures, including those starting with '_'
  413    extra_variables: HashMap<String, String>,
  414    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  415    context_range: Range<BufferOffset>,
  416}
  417
  418#[derive(Clone)]
  419struct ResolvedTasks {
  420    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  421    position: Anchor,
  422}
  423#[derive(Copy, Clone, Debug)]
  424struct MultiBufferOffset(usize);
  425#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  426struct BufferOffset(usize);
  427/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
  428///
  429/// See the [module level documentation](self) for more information.
  430pub struct Editor {
  431    focus_handle: FocusHandle,
  432    /// The text buffer being edited
  433    buffer: Model<MultiBuffer>,
  434    /// Map of how text in the buffer should be displayed.
  435    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  436    pub display_map: Model<DisplayMap>,
  437    pub selections: SelectionsCollection,
  438    pub scroll_manager: ScrollManager,
  439    columnar_selection_tail: Option<Anchor>,
  440    add_selections_state: Option<AddSelectionsState>,
  441    select_next_state: Option<SelectNextState>,
  442    select_prev_state: Option<SelectNextState>,
  443    selection_history: SelectionHistory,
  444    autoclose_regions: Vec<AutocloseRegion>,
  445    snippet_stack: InvalidationStack<SnippetState>,
  446    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  447    ime_transaction: Option<TransactionId>,
  448    active_diagnostics: Option<ActiveDiagnosticGroup>,
  449    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  450    project: Option<Model<Project>>,
  451    completion_provider: Option<Box<dyn CompletionProvider>>,
  452    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  453    blink_manager: Model<BlinkManager>,
  454    show_cursor_names: bool,
  455    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  456    pub show_local_selections: bool,
  457    mode: EditorMode,
  458    show_breadcrumbs: bool,
  459    show_gutter: bool,
  460    show_line_numbers: Option<bool>,
  461    show_git_diff_gutter: Option<bool>,
  462    show_code_actions: Option<bool>,
  463    show_wrap_guides: Option<bool>,
  464    show_indent_guides: Option<bool>,
  465    placeholder_text: Option<Arc<str>>,
  466    highlight_order: usize,
  467    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  468    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  469    scrollbar_marker_state: ScrollbarMarkerState,
  470    active_indent_guides_state: ActiveIndentGuidesState,
  471    nav_history: Option<ItemNavHistory>,
  472    context_menu: RwLock<Option<ContextMenu>>,
  473    mouse_context_menu: Option<MouseContextMenu>,
  474    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  475    find_all_references_task_sources: Vec<Anchor>,
  476    next_completion_id: CompletionId,
  477    completion_documentation_pre_resolve_debounce: DebouncedDelay,
  478    available_code_actions: Option<(Location, Arc<[CodeAction]>)>,
  479    code_actions_task: Option<Task<()>>,
  480    document_highlights_task: Option<Task<()>>,
  481    pending_rename: Option<RenameState>,
  482    searchable: bool,
  483    cursor_shape: CursorShape,
  484    current_line_highlight: CurrentLineHighlight,
  485    collapse_matches: bool,
  486    autoindent_mode: Option<AutoindentMode>,
  487    workspace: Option<(WeakView<Workspace>, WorkspaceId)>,
  488    keymap_context_layers: BTreeMap<TypeId, KeyContext>,
  489    input_enabled: bool,
  490    use_modal_editing: bool,
  491    read_only: bool,
  492    leader_peer_id: Option<PeerId>,
  493    remote_id: Option<ViewId>,
  494    hover_state: HoverState,
  495    gutter_hovered: bool,
  496    hovered_link_state: Option<HoveredLinkState>,
  497    inline_completion_provider: Option<RegisteredInlineCompletionProvider>,
  498    active_inline_completion: Option<Inlay>,
  499    show_inline_completions: bool,
  500    inlay_hint_cache: InlayHintCache,
  501    expanded_hunks: ExpandedHunks,
  502    next_inlay_id: usize,
  503    _subscriptions: Vec<Subscription>,
  504    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  505    gutter_dimensions: GutterDimensions,
  506    pub vim_replace_map: HashMap<Range<usize>, String>,
  507    style: Option<EditorStyle>,
  508    editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
  509    use_autoclose: bool,
  510    auto_replace_emoji_shortcode: bool,
  511    show_git_blame_gutter: bool,
  512    show_git_blame_inline: bool,
  513    show_git_blame_inline_delay_task: Option<Task<()>>,
  514    git_blame_inline_enabled: bool,
  515    blame: Option<Model<GitBlame>>,
  516    blame_subscription: Option<Subscription>,
  517    custom_context_menu: Option<
  518        Box<
  519            dyn 'static
  520                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
  521        >,
  522    >,
  523    last_bounds: Option<Bounds<Pixels>>,
  524    expect_bounds_change: Option<Bounds<Pixels>>,
  525    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  526    tasks_update_task: Option<Task<()>>,
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorSnapshot {
  531    pub mode: EditorMode,
  532    show_gutter: bool,
  533    show_line_numbers: Option<bool>,
  534    show_git_diff_gutter: Option<bool>,
  535    show_code_actions: Option<bool>,
  536    render_git_blame_gutter: bool,
  537    pub display_snapshot: DisplaySnapshot,
  538    pub placeholder_text: Option<Arc<str>>,
  539    is_focused: bool,
  540    scroll_anchor: ScrollAnchor,
  541    ongoing_scroll: OngoingScroll,
  542    current_line_highlight: CurrentLineHighlight,
  543    gutter_hovered: bool,
  544}
  545
  546const GIT_BLAME_GUTTER_WIDTH_CHARS: f32 = 53.;
  547
  548#[derive(Debug, Clone, Copy)]
  549pub struct GutterDimensions {
  550    pub left_padding: Pixels,
  551    pub right_padding: Pixels,
  552    pub width: Pixels,
  553    pub margin: Pixels,
  554    pub git_blame_entries_width: Option<Pixels>,
  555}
  556
  557impl Default for GutterDimensions {
  558    fn default() -> Self {
  559        Self {
  560            left_padding: Pixels::ZERO,
  561            right_padding: Pixels::ZERO,
  562            width: Pixels::ZERO,
  563            margin: Pixels::ZERO,
  564            git_blame_entries_width: None,
  565        }
  566    }
  567}
  568
  569#[derive(Debug)]
  570pub struct RemoteSelection {
  571    pub replica_id: ReplicaId,
  572    pub selection: Selection<Anchor>,
  573    pub cursor_shape: CursorShape,
  574    pub peer_id: PeerId,
  575    pub line_mode: bool,
  576    pub participant_index: Option<ParticipantIndex>,
  577    pub user_name: Option<SharedString>,
  578}
  579
  580#[derive(Clone, Debug)]
  581struct SelectionHistoryEntry {
  582    selections: Arc<[Selection<Anchor>]>,
  583    select_next_state: Option<SelectNextState>,
  584    select_prev_state: Option<SelectNextState>,
  585    add_selections_state: Option<AddSelectionsState>,
  586}
  587
  588enum SelectionHistoryMode {
  589    Normal,
  590    Undoing,
  591    Redoing,
  592}
  593
  594#[derive(Clone, PartialEq, Eq, Hash)]
  595struct HoveredCursor {
  596    replica_id: u16,
  597    selection_id: usize,
  598}
  599
  600impl Default for SelectionHistoryMode {
  601    fn default() -> Self {
  602        Self::Normal
  603    }
  604}
  605
  606#[derive(Default)]
  607struct SelectionHistory {
  608    #[allow(clippy::type_complexity)]
  609    selections_by_transaction:
  610        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  611    mode: SelectionHistoryMode,
  612    undo_stack: VecDeque<SelectionHistoryEntry>,
  613    redo_stack: VecDeque<SelectionHistoryEntry>,
  614}
  615
  616impl SelectionHistory {
  617    fn insert_transaction(
  618        &mut self,
  619        transaction_id: TransactionId,
  620        selections: Arc<[Selection<Anchor>]>,
  621    ) {
  622        self.selections_by_transaction
  623            .insert(transaction_id, (selections, None));
  624    }
  625
  626    #[allow(clippy::type_complexity)]
  627    fn transaction(
  628        &self,
  629        transaction_id: TransactionId,
  630    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  631        self.selections_by_transaction.get(&transaction_id)
  632    }
  633
  634    #[allow(clippy::type_complexity)]
  635    fn transaction_mut(
  636        &mut self,
  637        transaction_id: TransactionId,
  638    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  639        self.selections_by_transaction.get_mut(&transaction_id)
  640    }
  641
  642    fn push(&mut self, entry: SelectionHistoryEntry) {
  643        if !entry.selections.is_empty() {
  644            match self.mode {
  645                SelectionHistoryMode::Normal => {
  646                    self.push_undo(entry);
  647                    self.redo_stack.clear();
  648                }
  649                SelectionHistoryMode::Undoing => self.push_redo(entry),
  650                SelectionHistoryMode::Redoing => self.push_undo(entry),
  651            }
  652        }
  653    }
  654
  655    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  656        if self
  657            .undo_stack
  658            .back()
  659            .map_or(true, |e| e.selections != entry.selections)
  660        {
  661            self.undo_stack.push_back(entry);
  662            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  663                self.undo_stack.pop_front();
  664            }
  665        }
  666    }
  667
  668    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  669        if self
  670            .redo_stack
  671            .back()
  672            .map_or(true, |e| e.selections != entry.selections)
  673        {
  674            self.redo_stack.push_back(entry);
  675            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  676                self.redo_stack.pop_front();
  677            }
  678        }
  679    }
  680}
  681
  682struct RowHighlight {
  683    index: usize,
  684    range: RangeInclusive<Anchor>,
  685    color: Option<Hsla>,
  686    should_autoscroll: bool,
  687}
  688
  689#[derive(Clone, Debug)]
  690struct AddSelectionsState {
  691    above: bool,
  692    stack: Vec<usize>,
  693}
  694
  695#[derive(Clone)]
  696struct SelectNextState {
  697    query: AhoCorasick,
  698    wordwise: bool,
  699    done: bool,
  700}
  701
  702impl std::fmt::Debug for SelectNextState {
  703    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  704        f.debug_struct(std::any::type_name::<Self>())
  705            .field("wordwise", &self.wordwise)
  706            .field("done", &self.done)
  707            .finish()
  708    }
  709}
  710
  711#[derive(Debug)]
  712struct AutocloseRegion {
  713    selection_id: usize,
  714    range: Range<Anchor>,
  715    pair: BracketPair,
  716}
  717
  718#[derive(Debug)]
  719struct SnippetState {
  720    ranges: Vec<Vec<Range<Anchor>>>,
  721    active_index: usize,
  722}
  723
  724#[doc(hidden)]
  725pub struct RenameState {
  726    pub range: Range<Anchor>,
  727    pub old_name: Arc<str>,
  728    pub editor: View<Editor>,
  729    block_id: BlockId,
  730}
  731
  732struct InvalidationStack<T>(Vec<T>);
  733
  734struct RegisteredInlineCompletionProvider {
  735    provider: Arc<dyn InlineCompletionProviderHandle>,
  736    _subscription: Subscription,
  737}
  738
  739enum ContextMenu {
  740    Completions(CompletionsMenu),
  741    CodeActions(CodeActionsMenu),
  742}
  743
  744impl ContextMenu {
  745    fn select_first(
  746        &mut self,
  747        project: Option<&Model<Project>>,
  748        cx: &mut ViewContext<Editor>,
  749    ) -> bool {
  750        if self.visible() {
  751            match self {
  752                ContextMenu::Completions(menu) => menu.select_first(project, cx),
  753                ContextMenu::CodeActions(menu) => menu.select_first(cx),
  754            }
  755            true
  756        } else {
  757            false
  758        }
  759    }
  760
  761    fn select_prev(
  762        &mut self,
  763        project: Option<&Model<Project>>,
  764        cx: &mut ViewContext<Editor>,
  765    ) -> bool {
  766        if self.visible() {
  767            match self {
  768                ContextMenu::Completions(menu) => menu.select_prev(project, cx),
  769                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  770            }
  771            true
  772        } else {
  773            false
  774        }
  775    }
  776
  777    fn select_next(
  778        &mut self,
  779        project: Option<&Model<Project>>,
  780        cx: &mut ViewContext<Editor>,
  781    ) -> bool {
  782        if self.visible() {
  783            match self {
  784                ContextMenu::Completions(menu) => menu.select_next(project, cx),
  785                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  786            }
  787            true
  788        } else {
  789            false
  790        }
  791    }
  792
  793    fn select_last(
  794        &mut self,
  795        project: Option<&Model<Project>>,
  796        cx: &mut ViewContext<Editor>,
  797    ) -> bool {
  798        if self.visible() {
  799            match self {
  800                ContextMenu::Completions(menu) => menu.select_last(project, cx),
  801                ContextMenu::CodeActions(menu) => menu.select_last(cx),
  802            }
  803            true
  804        } else {
  805            false
  806        }
  807    }
  808
  809    fn visible(&self) -> bool {
  810        match self {
  811            ContextMenu::Completions(menu) => menu.visible(),
  812            ContextMenu::CodeActions(menu) => menu.visible(),
  813        }
  814    }
  815
  816    fn render(
  817        &self,
  818        cursor_position: DisplayPoint,
  819        style: &EditorStyle,
  820        max_height: Pixels,
  821        workspace: Option<WeakView<Workspace>>,
  822        cx: &mut ViewContext<Editor>,
  823    ) -> (ContextMenuOrigin, AnyElement) {
  824        match self {
  825            ContextMenu::Completions(menu) => (
  826                ContextMenuOrigin::EditorPoint(cursor_position),
  827                menu.render(style, max_height, workspace, cx),
  828            ),
  829            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
  830        }
  831    }
  832}
  833
  834enum ContextMenuOrigin {
  835    EditorPoint(DisplayPoint),
  836    GutterIndicator(DisplayRow),
  837}
  838
  839#[derive(Clone)]
  840struct CompletionsMenu {
  841    id: CompletionId,
  842    initial_position: Anchor,
  843    buffer: Model<Buffer>,
  844    completions: Arc<RwLock<Box<[Completion]>>>,
  845    match_candidates: Arc<[StringMatchCandidate]>,
  846    matches: Arc<[StringMatch]>,
  847    selected_item: usize,
  848    scroll_handle: UniformListScrollHandle,
  849    selected_completion_documentation_resolve_debounce: Arc<Mutex<DebouncedDelay>>,
  850}
  851
  852impl CompletionsMenu {
  853    fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  854        self.selected_item = 0;
  855        self.scroll_handle.scroll_to_item(self.selected_item);
  856        self.attempt_resolve_selected_completion_documentation(project, cx);
  857        cx.notify();
  858    }
  859
  860    fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  861        if self.selected_item > 0 {
  862            self.selected_item -= 1;
  863        } else {
  864            self.selected_item = self.matches.len() - 1;
  865        }
  866        self.scroll_handle.scroll_to_item(self.selected_item);
  867        self.attempt_resolve_selected_completion_documentation(project, cx);
  868        cx.notify();
  869    }
  870
  871    fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  872        if self.selected_item + 1 < self.matches.len() {
  873            self.selected_item += 1;
  874        } else {
  875            self.selected_item = 0;
  876        }
  877        self.scroll_handle.scroll_to_item(self.selected_item);
  878        self.attempt_resolve_selected_completion_documentation(project, cx);
  879        cx.notify();
  880    }
  881
  882    fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  883        self.selected_item = self.matches.len() - 1;
  884        self.scroll_handle.scroll_to_item(self.selected_item);
  885        self.attempt_resolve_selected_completion_documentation(project, cx);
  886        cx.notify();
  887    }
  888
  889    fn pre_resolve_completion_documentation(
  890        buffer: Model<Buffer>,
  891        completions: Arc<RwLock<Box<[Completion]>>>,
  892        matches: Arc<[StringMatch]>,
  893        editor: &Editor,
  894        cx: &mut ViewContext<Editor>,
  895    ) -> Task<()> {
  896        let settings = EditorSettings::get_global(cx);
  897        if !settings.show_completion_documentation {
  898            return Task::ready(());
  899        }
  900
  901        let Some(provider) = editor.completion_provider.as_ref() else {
  902            return Task::ready(());
  903        };
  904
  905        let resolve_task = provider.resolve_completions(
  906            buffer,
  907            matches.iter().map(|m| m.candidate_id).collect(),
  908            completions.clone(),
  909            cx,
  910        );
  911
  912        return cx.spawn(move |this, mut cx| async move {
  913            if let Some(true) = resolve_task.await.log_err() {
  914                this.update(&mut cx, |_, cx| cx.notify()).ok();
  915            }
  916        });
  917    }
  918
  919    fn attempt_resolve_selected_completion_documentation(
  920        &mut self,
  921        project: Option<&Model<Project>>,
  922        cx: &mut ViewContext<Editor>,
  923    ) {
  924        let settings = EditorSettings::get_global(cx);
  925        if !settings.show_completion_documentation {
  926            return;
  927        }
  928
  929        let completion_index = self.matches[self.selected_item].candidate_id;
  930        let Some(project) = project else {
  931            return;
  932        };
  933
  934        let resolve_task = project.update(cx, |project, cx| {
  935            project.resolve_completions(
  936                self.buffer.clone(),
  937                vec![completion_index],
  938                self.completions.clone(),
  939                cx,
  940            )
  941        });
  942
  943        let delay_ms =
  944            EditorSettings::get_global(cx).completion_documentation_secondary_query_debounce;
  945        let delay = Duration::from_millis(delay_ms);
  946
  947        self.selected_completion_documentation_resolve_debounce
  948            .lock()
  949            .fire_new(delay, cx, |_, cx| {
  950                cx.spawn(move |this, mut cx| async move {
  951                    if let Some(true) = resolve_task.await.log_err() {
  952                        this.update(&mut cx, |_, cx| cx.notify()).ok();
  953                    }
  954                })
  955            });
  956    }
  957
  958    fn visible(&self) -> bool {
  959        !self.matches.is_empty()
  960    }
  961
  962    fn render(
  963        &self,
  964        style: &EditorStyle,
  965        max_height: Pixels,
  966        workspace: Option<WeakView<Workspace>>,
  967        cx: &mut ViewContext<Editor>,
  968    ) -> AnyElement {
  969        let settings = EditorSettings::get_global(cx);
  970        let show_completion_documentation = settings.show_completion_documentation;
  971
  972        let widest_completion_ix = self
  973            .matches
  974            .iter()
  975            .enumerate()
  976            .max_by_key(|(_, mat)| {
  977                let completions = self.completions.read();
  978                let completion = &completions[mat.candidate_id];
  979                let documentation = &completion.documentation;
  980
  981                let mut len = completion.label.text.chars().count();
  982                if let Some(Documentation::SingleLine(text)) = documentation {
  983                    if show_completion_documentation {
  984                        len += text.chars().count();
  985                    }
  986                }
  987
  988                len
  989            })
  990            .map(|(ix, _)| ix);
  991
  992        let completions = self.completions.clone();
  993        let matches = self.matches.clone();
  994        let selected_item = self.selected_item;
  995        let style = style.clone();
  996
  997        let multiline_docs = if show_completion_documentation {
  998            let mat = &self.matches[selected_item];
  999            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
 1000                Some(Documentation::MultiLinePlainText(text)) => {
 1001                    Some(div().child(SharedString::from(text.clone())))
 1002                }
 1003                Some(Documentation::MultiLineMarkdown(parsed)) if !parsed.text.is_empty() => {
 1004                    Some(div().child(render_parsed_markdown(
 1005                        "completions_markdown",
 1006                        parsed,
 1007                        &style,
 1008                        workspace,
 1009                        cx,
 1010                    )))
 1011                }
 1012                _ => None,
 1013            };
 1014            multiline_docs.map(|div| {
 1015                div.id("multiline_docs")
 1016                    .max_h(max_height)
 1017                    .flex_1()
 1018                    .px_1p5()
 1019                    .py_1()
 1020                    .min_w(px(260.))
 1021                    .max_w(px(640.))
 1022                    .w(px(500.))
 1023                    .overflow_y_scroll()
 1024                    .occlude()
 1025            })
 1026        } else {
 1027            None
 1028        };
 1029
 1030        let list = uniform_list(
 1031            cx.view().clone(),
 1032            "completions",
 1033            matches.len(),
 1034            move |_editor, range, cx| {
 1035                let start_ix = range.start;
 1036                let completions_guard = completions.read();
 1037
 1038                matches[range]
 1039                    .iter()
 1040                    .enumerate()
 1041                    .map(|(ix, mat)| {
 1042                        let item_ix = start_ix + ix;
 1043                        let candidate_id = mat.candidate_id;
 1044                        let completion = &completions_guard[candidate_id];
 1045
 1046                        let documentation = if show_completion_documentation {
 1047                            &completion.documentation
 1048                        } else {
 1049                            &None
 1050                        };
 1051
 1052                        let highlights = gpui::combine_highlights(
 1053                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
 1054                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
 1055                                |(range, mut highlight)| {
 1056                                    // Ignore font weight for syntax highlighting, as we'll use it
 1057                                    // for fuzzy matches.
 1058                                    highlight.font_weight = None;
 1059
 1060                                    if completion.lsp_completion.deprecated.unwrap_or(false) {
 1061                                        highlight.strikethrough = Some(StrikethroughStyle {
 1062                                            thickness: 1.0.into(),
 1063                                            ..Default::default()
 1064                                        });
 1065                                        highlight.color = Some(cx.theme().colors().text_muted);
 1066                                    }
 1067
 1068                                    (range, highlight)
 1069                                },
 1070                            ),
 1071                        );
 1072                        let completion_label = StyledText::new(completion.label.text.clone())
 1073                            .with_highlights(&style.text, highlights);
 1074                        let documentation_label =
 1075                            if let Some(Documentation::SingleLine(text)) = documentation {
 1076                                if text.trim().is_empty() {
 1077                                    None
 1078                                } else {
 1079                                    Some(
 1080                                        h_flex().ml_4().child(
 1081                                            Label::new(text.clone())
 1082                                                .size(LabelSize::Small)
 1083                                                .color(Color::Muted),
 1084                                        ),
 1085                                    )
 1086                                }
 1087                            } else {
 1088                                None
 1089                            };
 1090
 1091                        div().min_w(px(220.)).max_w(px(540.)).child(
 1092                            ListItem::new(mat.candidate_id)
 1093                                .inset(true)
 1094                                .selected(item_ix == selected_item)
 1095                                .on_click(cx.listener(move |editor, _event, cx| {
 1096                                    cx.stop_propagation();
 1097                                    if let Some(task) = editor.confirm_completion(
 1098                                        &ConfirmCompletion {
 1099                                            item_ix: Some(item_ix),
 1100                                        },
 1101                                        cx,
 1102                                    ) {
 1103                                        task.detach_and_log_err(cx)
 1104                                    }
 1105                                }))
 1106                                .child(h_flex().overflow_hidden().child(completion_label))
 1107                                .end_slot::<Div>(documentation_label),
 1108                        )
 1109                    })
 1110                    .collect()
 1111            },
 1112        )
 1113        .occlude()
 1114        .max_h(max_height)
 1115        .track_scroll(self.scroll_handle.clone())
 1116        .with_width_from_item(widest_completion_ix);
 1117
 1118        Popover::new()
 1119            .child(list)
 1120            .when_some(multiline_docs, |popover, multiline_docs| {
 1121                popover.aside(multiline_docs)
 1122            })
 1123            .into_any_element()
 1124    }
 1125
 1126    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
 1127        let mut matches = if let Some(query) = query {
 1128            fuzzy::match_strings(
 1129                &self.match_candidates,
 1130                query,
 1131                query.chars().any(|c| c.is_uppercase()),
 1132                100,
 1133                &Default::default(),
 1134                executor,
 1135            )
 1136            .await
 1137        } else {
 1138            self.match_candidates
 1139                .iter()
 1140                .enumerate()
 1141                .map(|(candidate_id, candidate)| StringMatch {
 1142                    candidate_id,
 1143                    score: Default::default(),
 1144                    positions: Default::default(),
 1145                    string: candidate.string.clone(),
 1146                })
 1147                .collect()
 1148        };
 1149
 1150        // Remove all candidates where the query's start does not match the start of any word in the candidate
 1151        if let Some(query) = query {
 1152            if let Some(query_start) = query.chars().next() {
 1153                matches.retain(|string_match| {
 1154                    split_words(&string_match.string).any(|word| {
 1155                        // Check that the first codepoint of the word as lowercase matches the first
 1156                        // codepoint of the query as lowercase
 1157                        word.chars()
 1158                            .flat_map(|codepoint| codepoint.to_lowercase())
 1159                            .zip(query_start.to_lowercase())
 1160                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 1161                    })
 1162                });
 1163            }
 1164        }
 1165
 1166        let completions = self.completions.read();
 1167        matches.sort_unstable_by_key(|mat| {
 1168            // We do want to strike a balance here between what the language server tells us
 1169            // to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
 1170            // `Creat` and there is a local variable called `CreateComponent`).
 1171            // So what we do is: we bucket all matches into two buckets
 1172            // - Strong matches
 1173            // - Weak matches
 1174            // Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
 1175            // and the Weak matches are the rest.
 1176            //
 1177            // For the strong matches, we sort by the language-servers score first and for the weak
 1178            // matches, we prefer our fuzzy finder first.
 1179            //
 1180            // The thinking behind that: it's useless to take the sort_text the language-server gives
 1181            // us into account when it's obviously a bad match.
 1182
 1183            #[derive(PartialEq, Eq, PartialOrd, Ord)]
 1184            enum MatchScore<'a> {
 1185                Strong {
 1186                    sort_text: Option<&'a str>,
 1187                    score: Reverse<OrderedFloat<f64>>,
 1188                    sort_key: (usize, &'a str),
 1189                },
 1190                Weak {
 1191                    score: Reverse<OrderedFloat<f64>>,
 1192                    sort_text: Option<&'a str>,
 1193                    sort_key: (usize, &'a str),
 1194                },
 1195            }
 1196
 1197            let completion = &completions[mat.candidate_id];
 1198            let sort_key = completion.sort_key();
 1199            let sort_text = completion.lsp_completion.sort_text.as_deref();
 1200            let score = Reverse(OrderedFloat(mat.score));
 1201
 1202            if mat.score >= 0.2 {
 1203                MatchScore::Strong {
 1204                    sort_text,
 1205                    score,
 1206                    sort_key,
 1207                }
 1208            } else {
 1209                MatchScore::Weak {
 1210                    score,
 1211                    sort_text,
 1212                    sort_key,
 1213                }
 1214            }
 1215        });
 1216
 1217        for mat in &mut matches {
 1218            let completion = &completions[mat.candidate_id];
 1219            mat.string.clone_from(&completion.label.text);
 1220            for position in &mut mat.positions {
 1221                *position += completion.label.filter_range.start;
 1222            }
 1223        }
 1224        drop(completions);
 1225
 1226        self.matches = matches.into();
 1227        self.selected_item = 0;
 1228    }
 1229}
 1230
 1231#[derive(Clone)]
 1232struct CodeActionContents {
 1233    tasks: Option<Arc<ResolvedTasks>>,
 1234    actions: Option<Arc<[CodeAction]>>,
 1235}
 1236
 1237impl CodeActionContents {
 1238    fn len(&self) -> usize {
 1239        match (&self.tasks, &self.actions) {
 1240            (Some(tasks), Some(actions)) => actions.len() + tasks.templates.len(),
 1241            (Some(tasks), None) => tasks.templates.len(),
 1242            (None, Some(actions)) => actions.len(),
 1243            (None, None) => 0,
 1244        }
 1245    }
 1246
 1247    fn is_empty(&self) -> bool {
 1248        match (&self.tasks, &self.actions) {
 1249            (Some(tasks), Some(actions)) => actions.is_empty() && tasks.templates.is_empty(),
 1250            (Some(tasks), None) => tasks.templates.is_empty(),
 1251            (None, Some(actions)) => actions.is_empty(),
 1252            (None, None) => true,
 1253        }
 1254    }
 1255
 1256    fn iter(&self) -> impl Iterator<Item = CodeActionsItem> + '_ {
 1257        self.tasks
 1258            .iter()
 1259            .flat_map(|tasks| {
 1260                tasks
 1261                    .templates
 1262                    .iter()
 1263                    .map(|(kind, task)| CodeActionsItem::Task(kind.clone(), task.clone()))
 1264            })
 1265            .chain(self.actions.iter().flat_map(|actions| {
 1266                actions
 1267                    .iter()
 1268                    .map(|action| CodeActionsItem::CodeAction(action.clone()))
 1269            }))
 1270    }
 1271    fn get(&self, index: usize) -> Option<CodeActionsItem> {
 1272        match (&self.tasks, &self.actions) {
 1273            (Some(tasks), Some(actions)) => {
 1274                if index < tasks.templates.len() {
 1275                    tasks
 1276                        .templates
 1277                        .get(index)
 1278                        .cloned()
 1279                        .map(|(kind, task)| CodeActionsItem::Task(kind, task))
 1280                } else {
 1281                    actions
 1282                        .get(index - tasks.templates.len())
 1283                        .cloned()
 1284                        .map(CodeActionsItem::CodeAction)
 1285                }
 1286            }
 1287            (Some(tasks), None) => tasks
 1288                .templates
 1289                .get(index)
 1290                .cloned()
 1291                .map(|(kind, task)| CodeActionsItem::Task(kind, task)),
 1292            (None, Some(actions)) => actions.get(index).cloned().map(CodeActionsItem::CodeAction),
 1293            (None, None) => None,
 1294        }
 1295    }
 1296}
 1297
 1298#[allow(clippy::large_enum_variant)]
 1299#[derive(Clone)]
 1300enum CodeActionsItem {
 1301    Task(TaskSourceKind, ResolvedTask),
 1302    CodeAction(CodeAction),
 1303}
 1304
 1305impl CodeActionsItem {
 1306    fn as_task(&self) -> Option<&ResolvedTask> {
 1307        let Self::Task(_, task) = self else {
 1308            return None;
 1309        };
 1310        Some(task)
 1311    }
 1312    fn as_code_action(&self) -> Option<&CodeAction> {
 1313        let Self::CodeAction(action) = self else {
 1314            return None;
 1315        };
 1316        Some(action)
 1317    }
 1318    fn label(&self) -> String {
 1319        match self {
 1320            Self::CodeAction(action) => action.lsp_action.title.clone(),
 1321            Self::Task(_, task) => task.resolved_label.clone(),
 1322        }
 1323    }
 1324}
 1325
 1326struct CodeActionsMenu {
 1327    actions: CodeActionContents,
 1328    buffer: Model<Buffer>,
 1329    selected_item: usize,
 1330    scroll_handle: UniformListScrollHandle,
 1331    deployed_from_indicator: Option<DisplayRow>,
 1332}
 1333
 1334impl CodeActionsMenu {
 1335    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
 1336        self.selected_item = 0;
 1337        self.scroll_handle.scroll_to_item(self.selected_item);
 1338        cx.notify()
 1339    }
 1340
 1341    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 1342        if self.selected_item > 0 {
 1343            self.selected_item -= 1;
 1344        } else {
 1345            self.selected_item = self.actions.len() - 1;
 1346        }
 1347        self.scroll_handle.scroll_to_item(self.selected_item);
 1348        cx.notify();
 1349    }
 1350
 1351    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 1352        if self.selected_item + 1 < self.actions.len() {
 1353            self.selected_item += 1;
 1354        } else {
 1355            self.selected_item = 0;
 1356        }
 1357        self.scroll_handle.scroll_to_item(self.selected_item);
 1358        cx.notify();
 1359    }
 1360
 1361    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
 1362        self.selected_item = self.actions.len() - 1;
 1363        self.scroll_handle.scroll_to_item(self.selected_item);
 1364        cx.notify()
 1365    }
 1366
 1367    fn visible(&self) -> bool {
 1368        !self.actions.is_empty()
 1369    }
 1370
 1371    fn render(
 1372        &self,
 1373        cursor_position: DisplayPoint,
 1374        _style: &EditorStyle,
 1375        max_height: Pixels,
 1376        cx: &mut ViewContext<Editor>,
 1377    ) -> (ContextMenuOrigin, AnyElement) {
 1378        let actions = self.actions.clone();
 1379        let selected_item = self.selected_item;
 1380        let element = uniform_list(
 1381            cx.view().clone(),
 1382            "code_actions_menu",
 1383            self.actions.len(),
 1384            move |_this, range, cx| {
 1385                actions
 1386                    .iter()
 1387                    .skip(range.start)
 1388                    .take(range.end - range.start)
 1389                    .enumerate()
 1390                    .map(|(ix, action)| {
 1391                        let item_ix = range.start + ix;
 1392                        let selected = selected_item == item_ix;
 1393                        let colors = cx.theme().colors();
 1394                        div()
 1395                            .px_2()
 1396                            .text_color(colors.text)
 1397                            .when(selected, |style| {
 1398                                style
 1399                                    .bg(colors.element_active)
 1400                                    .text_color(colors.text_accent)
 1401                            })
 1402                            .hover(|style| {
 1403                                style
 1404                                    .bg(colors.element_hover)
 1405                                    .text_color(colors.text_accent)
 1406                            })
 1407                            .whitespace_nowrap()
 1408                            .when_some(action.as_code_action(), |this, action| {
 1409                                this.on_mouse_down(
 1410                                    MouseButton::Left,
 1411                                    cx.listener(move |editor, _, cx| {
 1412                                        cx.stop_propagation();
 1413                                        if let Some(task) = editor.confirm_code_action(
 1414                                            &ConfirmCodeAction {
 1415                                                item_ix: Some(item_ix),
 1416                                            },
 1417                                            cx,
 1418                                        ) {
 1419                                            task.detach_and_log_err(cx)
 1420                                        }
 1421                                    }),
 1422                                )
 1423                                // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
 1424                                .child(SharedString::from(action.lsp_action.title.clone()))
 1425                            })
 1426                            .when_some(action.as_task(), |this, task| {
 1427                                this.on_mouse_down(
 1428                                    MouseButton::Left,
 1429                                    cx.listener(move |editor, _, cx| {
 1430                                        cx.stop_propagation();
 1431                                        if let Some(task) = editor.confirm_code_action(
 1432                                            &ConfirmCodeAction {
 1433                                                item_ix: Some(item_ix),
 1434                                            },
 1435                                            cx,
 1436                                        ) {
 1437                                            task.detach_and_log_err(cx)
 1438                                        }
 1439                                    }),
 1440                                )
 1441                                .child(SharedString::from(task.resolved_label.clone()))
 1442                            })
 1443                    })
 1444                    .collect()
 1445            },
 1446        )
 1447        .elevation_1(cx)
 1448        .px_2()
 1449        .py_1()
 1450        .max_h(max_height)
 1451        .occlude()
 1452        .track_scroll(self.scroll_handle.clone())
 1453        .with_width_from_item(
 1454            self.actions
 1455                .iter()
 1456                .enumerate()
 1457                .max_by_key(|(_, action)| match action {
 1458                    CodeActionsItem::Task(_, task) => task.resolved_label.chars().count(),
 1459                    CodeActionsItem::CodeAction(action) => action.lsp_action.title.chars().count(),
 1460                })
 1461                .map(|(ix, _)| ix),
 1462        )
 1463        .into_any_element();
 1464
 1465        let cursor_position = if let Some(row) = self.deployed_from_indicator {
 1466            ContextMenuOrigin::GutterIndicator(row)
 1467        } else {
 1468            ContextMenuOrigin::EditorPoint(cursor_position)
 1469        };
 1470
 1471        (cursor_position, element)
 1472    }
 1473}
 1474
 1475#[derive(Debug)]
 1476struct ActiveDiagnosticGroup {
 1477    primary_range: Range<Anchor>,
 1478    primary_message: String,
 1479    group_id: usize,
 1480    blocks: HashMap<BlockId, Diagnostic>,
 1481    is_valid: bool,
 1482}
 1483
 1484#[derive(Serialize, Deserialize)]
 1485pub struct ClipboardSelection {
 1486    pub len: usize,
 1487    pub is_entire_line: bool,
 1488    pub first_line_indent: u32,
 1489}
 1490
 1491#[derive(Debug)]
 1492pub(crate) struct NavigationData {
 1493    cursor_anchor: Anchor,
 1494    cursor_position: Point,
 1495    scroll_anchor: ScrollAnchor,
 1496    scroll_top_row: u32,
 1497}
 1498
 1499enum GotoDefinitionKind {
 1500    Symbol,
 1501    Type,
 1502    Implementation,
 1503}
 1504
 1505#[derive(Debug, Clone)]
 1506enum InlayHintRefreshReason {
 1507    Toggle(bool),
 1508    SettingsChange(InlayHintSettings),
 1509    NewLinesShown,
 1510    BufferEdited(HashSet<Arc<Language>>),
 1511    RefreshRequested,
 1512    ExcerptsRemoved(Vec<ExcerptId>),
 1513}
 1514
 1515impl InlayHintRefreshReason {
 1516    fn description(&self) -> &'static str {
 1517        match self {
 1518            Self::Toggle(_) => "toggle",
 1519            Self::SettingsChange(_) => "settings change",
 1520            Self::NewLinesShown => "new lines shown",
 1521            Self::BufferEdited(_) => "buffer edited",
 1522            Self::RefreshRequested => "refresh requested",
 1523            Self::ExcerptsRemoved(_) => "excerpts removed",
 1524        }
 1525    }
 1526}
 1527
 1528impl Editor {
 1529    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
 1530        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1531        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1532        Self::new(EditorMode::SingleLine, buffer, None, cx)
 1533    }
 1534
 1535    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
 1536        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1537        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1538        Self::new(EditorMode::Full, buffer, None, cx)
 1539    }
 1540
 1541    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
 1542        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1543        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1544        Self::new(EditorMode::AutoHeight { max_lines }, buffer, None, cx)
 1545    }
 1546
 1547    pub fn for_buffer(
 1548        buffer: Model<Buffer>,
 1549        project: Option<Model<Project>>,
 1550        cx: &mut ViewContext<Self>,
 1551    ) -> Self {
 1552        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1553        Self::new(EditorMode::Full, buffer, project, cx)
 1554    }
 1555
 1556    pub fn for_multibuffer(
 1557        buffer: Model<MultiBuffer>,
 1558        project: Option<Model<Project>>,
 1559        cx: &mut ViewContext<Self>,
 1560    ) -> Self {
 1561        Self::new(EditorMode::Full, buffer, project, cx)
 1562    }
 1563
 1564    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 1565        let mut clone = Self::new(self.mode, self.buffer.clone(), self.project.clone(), cx);
 1566        self.display_map.update(cx, |display_map, cx| {
 1567            let snapshot = display_map.snapshot(cx);
 1568            clone.display_map.update(cx, |display_map, cx| {
 1569                display_map.set_state(&snapshot, cx);
 1570            });
 1571        });
 1572        clone.selections.clone_state(&self.selections);
 1573        clone.scroll_manager.clone_state(&self.scroll_manager);
 1574        clone.searchable = self.searchable;
 1575        clone
 1576    }
 1577
 1578    fn new(
 1579        mode: EditorMode,
 1580        buffer: Model<MultiBuffer>,
 1581        project: Option<Model<Project>>,
 1582        cx: &mut ViewContext<Self>,
 1583    ) -> Self {
 1584        let style = cx.text_style();
 1585        let font_size = style.font_size.to_pixels(cx.rem_size());
 1586        let editor = cx.view().downgrade();
 1587        let fold_placeholder = FoldPlaceholder {
 1588            constrain_width: true,
 1589            render: Arc::new(move |fold_id, fold_range, cx| {
 1590                let editor = editor.clone();
 1591                div()
 1592                    .id(fold_id)
 1593                    .bg(cx.theme().colors().ghost_element_background)
 1594                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1595                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1596                    .rounded_sm()
 1597                    .size_full()
 1598                    .cursor_pointer()
 1599                    .child("")
 1600                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 1601                    .on_click(move |_, cx| {
 1602                        editor
 1603                            .update(cx, |editor, cx| {
 1604                                editor.unfold_ranges(
 1605                                    [fold_range.start..fold_range.end],
 1606                                    true,
 1607                                    false,
 1608                                    cx,
 1609                                );
 1610                                cx.stop_propagation();
 1611                            })
 1612                            .ok();
 1613                    })
 1614                    .into_any()
 1615            }),
 1616        };
 1617        let display_map = cx.new_model(|cx| {
 1618            DisplayMap::new(
 1619                buffer.clone(),
 1620                style.font(),
 1621                font_size,
 1622                None,
 1623                2,
 1624                1,
 1625                fold_placeholder,
 1626                cx,
 1627            )
 1628        });
 1629
 1630        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1631
 1632        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1633
 1634        let soft_wrap_mode_override =
 1635            (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::PreferLine);
 1636
 1637        let mut project_subscriptions = Vec::new();
 1638        if mode == EditorMode::Full {
 1639            if let Some(project) = project.as_ref() {
 1640                if buffer.read(cx).is_singleton() {
 1641                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
 1642                        cx.emit(EditorEvent::TitleChanged);
 1643                    }));
 1644                }
 1645                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
 1646                    if let project::Event::RefreshInlayHints = event {
 1647                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1648                    } else if let project::Event::SnippetEdit(id, snippet_edits) = event {
 1649                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1650                            let focus_handle = editor.focus_handle(cx);
 1651                            if focus_handle.is_focused(cx) {
 1652                                let snapshot = buffer.read(cx).snapshot();
 1653                                for (range, snippet) in snippet_edits {
 1654                                    let editor_range =
 1655                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1656                                    editor
 1657                                        .insert_snippet(&[editor_range], snippet.clone(), cx)
 1658                                        .ok();
 1659                                }
 1660                            }
 1661                        }
 1662                    }
 1663                }));
 1664                let task_inventory = project.read(cx).task_inventory().clone();
 1665                project_subscriptions.push(cx.observe(&task_inventory, |editor, _, cx| {
 1666                    editor.tasks_update_task = Some(editor.refresh_runnables(cx));
 1667                }));
 1668            }
 1669        }
 1670
 1671        let inlay_hint_settings = inlay_hint_settings(
 1672            selections.newest_anchor().head(),
 1673            &buffer.read(cx).snapshot(cx),
 1674            cx,
 1675        );
 1676        let focus_handle = cx.focus_handle();
 1677        cx.on_focus(&focus_handle, Self::handle_focus).detach();
 1678        cx.on_blur(&focus_handle, Self::handle_blur).detach();
 1679
 1680        let mut this = Self {
 1681            focus_handle,
 1682            buffer: buffer.clone(),
 1683            display_map: display_map.clone(),
 1684            selections,
 1685            scroll_manager: ScrollManager::new(cx),
 1686            columnar_selection_tail: None,
 1687            add_selections_state: None,
 1688            select_next_state: None,
 1689            select_prev_state: None,
 1690            selection_history: Default::default(),
 1691            autoclose_regions: Default::default(),
 1692            snippet_stack: Default::default(),
 1693            select_larger_syntax_node_stack: Vec::new(),
 1694            ime_transaction: Default::default(),
 1695            active_diagnostics: None,
 1696            soft_wrap_mode_override,
 1697            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1698            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1699            project,
 1700            blink_manager: blink_manager.clone(),
 1701            show_local_selections: true,
 1702            mode,
 1703            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1704            show_gutter: mode == EditorMode::Full,
 1705            show_line_numbers: None,
 1706            show_git_diff_gutter: None,
 1707            show_code_actions: None,
 1708            show_wrap_guides: None,
 1709            show_indent_guides: None,
 1710            placeholder_text: None,
 1711            highlight_order: 0,
 1712            highlighted_rows: HashMap::default(),
 1713            background_highlights: Default::default(),
 1714            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1715            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1716            nav_history: None,
 1717            context_menu: RwLock::new(None),
 1718            mouse_context_menu: None,
 1719            completion_tasks: Default::default(),
 1720            find_all_references_task_sources: Vec::new(),
 1721            next_completion_id: 0,
 1722            completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
 1723            next_inlay_id: 0,
 1724            available_code_actions: Default::default(),
 1725            code_actions_task: Default::default(),
 1726            document_highlights_task: Default::default(),
 1727            pending_rename: Default::default(),
 1728            searchable: true,
 1729            cursor_shape: Default::default(),
 1730            current_line_highlight: EditorSettings::get_global(cx).current_line_highlight,
 1731            autoindent_mode: Some(AutoindentMode::EachLine),
 1732            collapse_matches: false,
 1733            workspace: None,
 1734            keymap_context_layers: Default::default(),
 1735            input_enabled: true,
 1736            use_modal_editing: mode == EditorMode::Full,
 1737            read_only: false,
 1738            use_autoclose: true,
 1739            auto_replace_emoji_shortcode: false,
 1740            leader_peer_id: None,
 1741            remote_id: None,
 1742            hover_state: Default::default(),
 1743            hovered_link_state: Default::default(),
 1744            inline_completion_provider: None,
 1745            active_inline_completion: None,
 1746            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1747            expanded_hunks: ExpandedHunks::default(),
 1748            gutter_hovered: false,
 1749            pixel_position_of_newest_cursor: None,
 1750            last_bounds: None,
 1751            expect_bounds_change: None,
 1752            gutter_dimensions: GutterDimensions::default(),
 1753            style: None,
 1754            show_cursor_names: false,
 1755            hovered_cursors: Default::default(),
 1756            editor_actions: Default::default(),
 1757            vim_replace_map: Default::default(),
 1758            show_inline_completions: mode == EditorMode::Full,
 1759            custom_context_menu: None,
 1760            show_git_blame_gutter: false,
 1761            show_git_blame_inline: false,
 1762            show_git_blame_inline_delay_task: None,
 1763            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1764            blame: None,
 1765            blame_subscription: None,
 1766            tasks: Default::default(),
 1767            _subscriptions: vec![
 1768                cx.observe(&buffer, Self::on_buffer_changed),
 1769                cx.subscribe(&buffer, Self::on_buffer_event),
 1770                cx.observe(&display_map, Self::on_display_map_changed),
 1771                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1772                cx.observe_global::<SettingsStore>(Self::settings_changed),
 1773                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1774                cx.observe_window_activation(|editor, cx| {
 1775                    let active = cx.is_window_active();
 1776                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1777                        if active {
 1778                            blink_manager.enable(cx);
 1779                        } else {
 1780                            blink_manager.show_cursor(cx);
 1781                            blink_manager.disable(cx);
 1782                        }
 1783                    });
 1784                }),
 1785            ],
 1786            tasks_update_task: None,
 1787        };
 1788        this.tasks_update_task = Some(this.refresh_runnables(cx));
 1789        this._subscriptions.extend(project_subscriptions);
 1790
 1791        this.end_selection(cx);
 1792        this.scroll_manager.show_scrollbar(cx);
 1793
 1794        if mode == EditorMode::Full {
 1795            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1796            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1797
 1798            if this.git_blame_inline_enabled {
 1799                this.git_blame_inline_enabled = true;
 1800                this.start_git_blame_inline(false, cx);
 1801            }
 1802        }
 1803
 1804        this.report_editor_event("open", None, cx);
 1805        this
 1806    }
 1807
 1808    pub fn mouse_menu_is_focused(&self, cx: &mut WindowContext) -> bool {
 1809        self.mouse_context_menu
 1810            .as_ref()
 1811            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(cx))
 1812    }
 1813
 1814    fn key_context(&self, cx: &AppContext) -> KeyContext {
 1815        let mut key_context = KeyContext::new_with_defaults();
 1816        key_context.add("Editor");
 1817        let mode = match self.mode {
 1818            EditorMode::SingleLine => "single_line",
 1819            EditorMode::AutoHeight { .. } => "auto_height",
 1820            EditorMode::Full => "full",
 1821        };
 1822        key_context.set("mode", mode);
 1823        if self.pending_rename.is_some() {
 1824            key_context.add("renaming");
 1825        }
 1826        if self.context_menu_visible() {
 1827            match self.context_menu.read().as_ref() {
 1828                Some(ContextMenu::Completions(_)) => {
 1829                    key_context.add("menu");
 1830                    key_context.add("showing_completions")
 1831                }
 1832                Some(ContextMenu::CodeActions(_)) => {
 1833                    key_context.add("menu");
 1834                    key_context.add("showing_code_actions")
 1835                }
 1836                None => {}
 1837            }
 1838        }
 1839
 1840        for layer in self.keymap_context_layers.values() {
 1841            key_context.extend(layer);
 1842        }
 1843
 1844        if let Some(extension) = self
 1845            .buffer
 1846            .read(cx)
 1847            .as_singleton()
 1848            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 1849        {
 1850            key_context.set("extension", extension.to_string());
 1851        }
 1852
 1853        if self.has_active_inline_completion(cx) {
 1854            key_context.add("copilot_suggestion");
 1855            key_context.add("inline_completion");
 1856        }
 1857
 1858        key_context
 1859    }
 1860
 1861    pub fn new_file(
 1862        workspace: &mut Workspace,
 1863        _: &workspace::NewFile,
 1864        cx: &mut ViewContext<Workspace>,
 1865    ) {
 1866        let project = workspace.project().clone();
 1867        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1868
 1869        cx.spawn(|workspace, mut cx| async move {
 1870            let buffer = create.await?;
 1871            workspace.update(&mut cx, |workspace, cx| {
 1872                workspace.add_item_to_active_pane(
 1873                    Box::new(
 1874                        cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
 1875                    ),
 1876                    None,
 1877                    cx,
 1878                )
 1879            })
 1880        })
 1881        .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
 1882            ErrorCode::RemoteUpgradeRequired => Some(format!(
 1883                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1884                e.error_tag("required").unwrap_or("the latest version")
 1885            )),
 1886            _ => None,
 1887        });
 1888    }
 1889
 1890    pub fn new_file_in_direction(
 1891        workspace: &mut Workspace,
 1892        action: &workspace::NewFileInDirection,
 1893        cx: &mut ViewContext<Workspace>,
 1894    ) {
 1895        let project = workspace.project().clone();
 1896        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1897        let direction = action.0;
 1898
 1899        cx.spawn(|workspace, mut cx| async move {
 1900            let buffer = create.await?;
 1901            workspace.update(&mut cx, move |workspace, cx| {
 1902                workspace.split_item(
 1903                    direction,
 1904                    Box::new(
 1905                        cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
 1906                    ),
 1907                    cx,
 1908                )
 1909            })?;
 1910            anyhow::Ok(())
 1911        })
 1912        .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
 1913            ErrorCode::RemoteUpgradeRequired => Some(format!(
 1914                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1915                e.error_tag("required").unwrap_or("the latest version")
 1916            )),
 1917            _ => None,
 1918        });
 1919    }
 1920
 1921    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
 1922        self.buffer.read(cx).replica_id()
 1923    }
 1924
 1925    pub fn leader_peer_id(&self) -> Option<PeerId> {
 1926        self.leader_peer_id
 1927    }
 1928
 1929    pub fn buffer(&self) -> &Model<MultiBuffer> {
 1930        &self.buffer
 1931    }
 1932
 1933    pub fn workspace(&self) -> Option<View<Workspace>> {
 1934        self.workspace.as_ref()?.0.upgrade()
 1935    }
 1936
 1937    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
 1938        self.buffer().read(cx).title(cx)
 1939    }
 1940
 1941    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
 1942        EditorSnapshot {
 1943            mode: self.mode,
 1944            show_gutter: self.show_gutter,
 1945            show_line_numbers: self.show_line_numbers,
 1946            show_git_diff_gutter: self.show_git_diff_gutter,
 1947            show_code_actions: self.show_code_actions,
 1948            render_git_blame_gutter: self.render_git_blame_gutter(cx),
 1949            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1950            scroll_anchor: self.scroll_manager.anchor(),
 1951            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 1952            placeholder_text: self.placeholder_text.clone(),
 1953            is_focused: self.focus_handle.is_focused(cx),
 1954            current_line_highlight: self.current_line_highlight,
 1955            gutter_hovered: self.gutter_hovered,
 1956        }
 1957    }
 1958
 1959    pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
 1960        self.buffer.read(cx).language_at(point, cx)
 1961    }
 1962
 1963    pub fn file_at<T: ToOffset>(
 1964        &self,
 1965        point: T,
 1966        cx: &AppContext,
 1967    ) -> Option<Arc<dyn language::File>> {
 1968        self.buffer.read(cx).read(cx).file_at(point).cloned()
 1969    }
 1970
 1971    pub fn active_excerpt(
 1972        &self,
 1973        cx: &AppContext,
 1974    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
 1975        self.buffer
 1976            .read(cx)
 1977            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 1978    }
 1979
 1980    pub fn mode(&self) -> EditorMode {
 1981        self.mode
 1982    }
 1983
 1984    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 1985        self.collaboration_hub.as_deref()
 1986    }
 1987
 1988    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 1989        self.collaboration_hub = Some(hub);
 1990    }
 1991
 1992    pub fn set_custom_context_menu(
 1993        &mut self,
 1994        f: impl 'static
 1995            + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
 1996    ) {
 1997        self.custom_context_menu = Some(Box::new(f))
 1998    }
 1999
 2000    pub fn set_completion_provider(&mut self, provider: Box<dyn CompletionProvider>) {
 2001        self.completion_provider = Some(provider);
 2002    }
 2003
 2004    pub fn set_inline_completion_provider<T>(
 2005        &mut self,
 2006        provider: Option<Model<T>>,
 2007        cx: &mut ViewContext<Self>,
 2008    ) where
 2009        T: InlineCompletionProvider,
 2010    {
 2011        self.inline_completion_provider =
 2012            provider.map(|provider| RegisteredInlineCompletionProvider {
 2013                _subscription: cx.observe(&provider, |this, _, cx| {
 2014                    if this.focus_handle.is_focused(cx) {
 2015                        this.update_visible_inline_completion(cx);
 2016                    }
 2017                }),
 2018                provider: Arc::new(provider),
 2019            });
 2020        self.refresh_inline_completion(false, cx);
 2021    }
 2022
 2023    pub fn placeholder_text(&self, _cx: &mut WindowContext) -> Option<&str> {
 2024        self.placeholder_text.as_deref()
 2025    }
 2026
 2027    pub fn set_placeholder_text(
 2028        &mut self,
 2029        placeholder_text: impl Into<Arc<str>>,
 2030        cx: &mut ViewContext<Self>,
 2031    ) {
 2032        let placeholder_text = Some(placeholder_text.into());
 2033        if self.placeholder_text != placeholder_text {
 2034            self.placeholder_text = placeholder_text;
 2035            cx.notify();
 2036        }
 2037    }
 2038
 2039    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 2040        self.cursor_shape = cursor_shape;
 2041        cx.notify();
 2042    }
 2043
 2044    pub fn set_current_line_highlight(&mut self, current_line_highlight: CurrentLineHighlight) {
 2045        self.current_line_highlight = current_line_highlight;
 2046    }
 2047
 2048    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2049        self.collapse_matches = collapse_matches;
 2050    }
 2051
 2052    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2053        if self.collapse_matches {
 2054            return range.start..range.start;
 2055        }
 2056        range.clone()
 2057    }
 2058
 2059    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 2060        if self.display_map.read(cx).clip_at_line_ends != clip {
 2061            self.display_map
 2062                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2063        }
 2064    }
 2065
 2066    pub fn set_keymap_context_layer<Tag: 'static>(
 2067        &mut self,
 2068        context: KeyContext,
 2069        cx: &mut ViewContext<Self>,
 2070    ) {
 2071        self.keymap_context_layers
 2072            .insert(TypeId::of::<Tag>(), context);
 2073        cx.notify();
 2074    }
 2075
 2076    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
 2077        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
 2078        cx.notify();
 2079    }
 2080
 2081    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2082        self.input_enabled = input_enabled;
 2083    }
 2084
 2085    pub fn set_autoindent(&mut self, autoindent: bool) {
 2086        if autoindent {
 2087            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2088        } else {
 2089            self.autoindent_mode = None;
 2090        }
 2091    }
 2092
 2093    pub fn read_only(&self, cx: &AppContext) -> bool {
 2094        self.read_only || self.buffer.read(cx).read_only()
 2095    }
 2096
 2097    pub fn set_read_only(&mut self, read_only: bool) {
 2098        self.read_only = read_only;
 2099    }
 2100
 2101    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2102        self.use_autoclose = autoclose;
 2103    }
 2104
 2105    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2106        self.auto_replace_emoji_shortcode = auto_replace;
 2107    }
 2108
 2109    pub fn set_show_inline_completions(&mut self, show_inline_completions: bool) {
 2110        self.show_inline_completions = show_inline_completions;
 2111    }
 2112
 2113    pub fn set_use_modal_editing(&mut self, to: bool) {
 2114        self.use_modal_editing = to;
 2115    }
 2116
 2117    pub fn use_modal_editing(&self) -> bool {
 2118        self.use_modal_editing
 2119    }
 2120
 2121    fn selections_did_change(
 2122        &mut self,
 2123        local: bool,
 2124        old_cursor_position: &Anchor,
 2125        show_completions: bool,
 2126        cx: &mut ViewContext<Self>,
 2127    ) {
 2128        // Copy selections to primary selection buffer
 2129        #[cfg(target_os = "linux")]
 2130        if local {
 2131            let selections = self.selections.all::<usize>(cx);
 2132            let buffer_handle = self.buffer.read(cx).read(cx);
 2133
 2134            let mut text = String::new();
 2135            for (index, selection) in selections.iter().enumerate() {
 2136                let text_for_selection = buffer_handle
 2137                    .text_for_range(selection.start..selection.end)
 2138                    .collect::<String>();
 2139
 2140                text.push_str(&text_for_selection);
 2141                if index != selections.len() - 1 {
 2142                    text.push('\n');
 2143                }
 2144            }
 2145
 2146            if !text.is_empty() {
 2147                cx.write_to_primary(ClipboardItem::new(text));
 2148            }
 2149        }
 2150
 2151        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
 2152            self.buffer.update(cx, |buffer, cx| {
 2153                buffer.set_active_selections(
 2154                    &self.selections.disjoint_anchors(),
 2155                    self.selections.line_mode,
 2156                    self.cursor_shape,
 2157                    cx,
 2158                )
 2159            });
 2160        }
 2161
 2162        let display_map = self
 2163            .display_map
 2164            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2165        let buffer = &display_map.buffer_snapshot;
 2166        self.add_selections_state = None;
 2167        self.select_next_state = None;
 2168        self.select_prev_state = None;
 2169        self.select_larger_syntax_node_stack.clear();
 2170        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2171        self.snippet_stack
 2172            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2173        self.take_rename(false, cx);
 2174
 2175        let new_cursor_position = self.selections.newest_anchor().head();
 2176
 2177        self.push_to_nav_history(
 2178            *old_cursor_position,
 2179            Some(new_cursor_position.to_point(buffer)),
 2180            cx,
 2181        );
 2182
 2183        if local {
 2184            let new_cursor_position = self.selections.newest_anchor().head();
 2185            let mut context_menu = self.context_menu.write();
 2186            let completion_menu = match context_menu.as_ref() {
 2187                Some(ContextMenu::Completions(menu)) => Some(menu),
 2188
 2189                _ => {
 2190                    *context_menu = None;
 2191                    None
 2192                }
 2193            };
 2194
 2195            if let Some(completion_menu) = completion_menu {
 2196                let cursor_position = new_cursor_position.to_offset(buffer);
 2197                let (word_range, kind) = buffer.surrounding_word(completion_menu.initial_position);
 2198                if kind == Some(CharKind::Word)
 2199                    && word_range.to_inclusive().contains(&cursor_position)
 2200                {
 2201                    let mut completion_menu = completion_menu.clone();
 2202                    drop(context_menu);
 2203
 2204                    let query = Self::completion_query(buffer, cursor_position);
 2205                    cx.spawn(move |this, mut cx| async move {
 2206                        completion_menu
 2207                            .filter(query.as_deref(), cx.background_executor().clone())
 2208                            .await;
 2209
 2210                        this.update(&mut cx, |this, cx| {
 2211                            let mut context_menu = this.context_menu.write();
 2212                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
 2213                                return;
 2214                            };
 2215
 2216                            if menu.id > completion_menu.id {
 2217                                return;
 2218                            }
 2219
 2220                            *context_menu = Some(ContextMenu::Completions(completion_menu));
 2221                            drop(context_menu);
 2222                            cx.notify();
 2223                        })
 2224                    })
 2225                    .detach();
 2226
 2227                    if show_completions {
 2228                        self.show_completions(&ShowCompletions, cx);
 2229                    }
 2230                } else {
 2231                    drop(context_menu);
 2232                    self.hide_context_menu(cx);
 2233                }
 2234            } else {
 2235                drop(context_menu);
 2236            }
 2237
 2238            hide_hover(self, cx);
 2239
 2240            if old_cursor_position.to_display_point(&display_map).row()
 2241                != new_cursor_position.to_display_point(&display_map).row()
 2242            {
 2243                self.available_code_actions.take();
 2244            }
 2245            self.refresh_code_actions(cx);
 2246            self.refresh_document_highlights(cx);
 2247            refresh_matching_bracket_highlights(self, cx);
 2248            self.discard_inline_completion(false, cx);
 2249            if self.git_blame_inline_enabled {
 2250                self.start_inline_blame_timer(cx);
 2251            }
 2252        }
 2253
 2254        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2255        cx.emit(EditorEvent::SelectionsChanged { local });
 2256
 2257        if self.selections.disjoint_anchors().len() == 1 {
 2258            cx.emit(SearchEvent::ActiveMatchChanged)
 2259        }
 2260
 2261        cx.notify();
 2262    }
 2263
 2264    pub fn change_selections<R>(
 2265        &mut self,
 2266        autoscroll: Option<Autoscroll>,
 2267        cx: &mut ViewContext<Self>,
 2268        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2269    ) -> R {
 2270        self.change_selections_inner(autoscroll, true, cx, change)
 2271    }
 2272
 2273    pub fn change_selections_inner<R>(
 2274        &mut self,
 2275        autoscroll: Option<Autoscroll>,
 2276        request_completions: bool,
 2277        cx: &mut ViewContext<Self>,
 2278        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2279    ) -> R {
 2280        let old_cursor_position = self.selections.newest_anchor().head();
 2281        self.push_to_selection_history();
 2282
 2283        let (changed, result) = self.selections.change_with(cx, change);
 2284
 2285        if changed {
 2286            if let Some(autoscroll) = autoscroll {
 2287                self.request_autoscroll(autoscroll, cx);
 2288            }
 2289            self.selections_did_change(true, &old_cursor_position, request_completions, cx);
 2290        }
 2291
 2292        result
 2293    }
 2294
 2295    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2296    where
 2297        I: IntoIterator<Item = (Range<S>, T)>,
 2298        S: ToOffset,
 2299        T: Into<Arc<str>>,
 2300    {
 2301        if self.read_only(cx) {
 2302            return;
 2303        }
 2304
 2305        self.buffer
 2306            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2307    }
 2308
 2309    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2310    where
 2311        I: IntoIterator<Item = (Range<S>, T)>,
 2312        S: ToOffset,
 2313        T: Into<Arc<str>>,
 2314    {
 2315        if self.read_only(cx) {
 2316            return;
 2317        }
 2318
 2319        self.buffer.update(cx, |buffer, cx| {
 2320            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2321        });
 2322    }
 2323
 2324    pub fn edit_with_block_indent<I, S, T>(
 2325        &mut self,
 2326        edits: I,
 2327        original_indent_columns: Vec<u32>,
 2328        cx: &mut ViewContext<Self>,
 2329    ) where
 2330        I: IntoIterator<Item = (Range<S>, T)>,
 2331        S: ToOffset,
 2332        T: Into<Arc<str>>,
 2333    {
 2334        if self.read_only(cx) {
 2335            return;
 2336        }
 2337
 2338        self.buffer.update(cx, |buffer, cx| {
 2339            buffer.edit(
 2340                edits,
 2341                Some(AutoindentMode::Block {
 2342                    original_indent_columns,
 2343                }),
 2344                cx,
 2345            )
 2346        });
 2347    }
 2348
 2349    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
 2350        self.hide_context_menu(cx);
 2351
 2352        match phase {
 2353            SelectPhase::Begin {
 2354                position,
 2355                add,
 2356                click_count,
 2357            } => self.begin_selection(position, add, click_count, cx),
 2358            SelectPhase::BeginColumnar {
 2359                position,
 2360                goal_column,
 2361                reset,
 2362            } => self.begin_columnar_selection(position, goal_column, reset, cx),
 2363            SelectPhase::Extend {
 2364                position,
 2365                click_count,
 2366            } => self.extend_selection(position, click_count, cx),
 2367            SelectPhase::Update {
 2368                position,
 2369                goal_column,
 2370                scroll_delta,
 2371            } => self.update_selection(position, goal_column, scroll_delta, cx),
 2372            SelectPhase::End => self.end_selection(cx),
 2373        }
 2374    }
 2375
 2376    fn extend_selection(
 2377        &mut self,
 2378        position: DisplayPoint,
 2379        click_count: usize,
 2380        cx: &mut ViewContext<Self>,
 2381    ) {
 2382        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2383        let tail = self.selections.newest::<usize>(cx).tail();
 2384        self.begin_selection(position, false, click_count, cx);
 2385
 2386        let position = position.to_offset(&display_map, Bias::Left);
 2387        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2388
 2389        let mut pending_selection = self
 2390            .selections
 2391            .pending_anchor()
 2392            .expect("extend_selection not called with pending selection");
 2393        if position >= tail {
 2394            pending_selection.start = tail_anchor;
 2395        } else {
 2396            pending_selection.end = tail_anchor;
 2397            pending_selection.reversed = true;
 2398        }
 2399
 2400        let mut pending_mode = self.selections.pending_mode().unwrap();
 2401        match &mut pending_mode {
 2402            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2403            _ => {}
 2404        }
 2405
 2406        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2407            s.set_pending(pending_selection, pending_mode)
 2408        });
 2409    }
 2410
 2411    fn begin_selection(
 2412        &mut self,
 2413        position: DisplayPoint,
 2414        add: bool,
 2415        click_count: usize,
 2416        cx: &mut ViewContext<Self>,
 2417    ) {
 2418        if !self.focus_handle.is_focused(cx) {
 2419            cx.focus(&self.focus_handle);
 2420        }
 2421
 2422        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2423        let buffer = &display_map.buffer_snapshot;
 2424        let newest_selection = self.selections.newest_anchor().clone();
 2425        let position = display_map.clip_point(position, Bias::Left);
 2426
 2427        let start;
 2428        let end;
 2429        let mode;
 2430        let auto_scroll;
 2431        match click_count {
 2432            1 => {
 2433                start = buffer.anchor_before(position.to_point(&display_map));
 2434                end = start;
 2435                mode = SelectMode::Character;
 2436                auto_scroll = true;
 2437            }
 2438            2 => {
 2439                let range = movement::surrounding_word(&display_map, position);
 2440                start = buffer.anchor_before(range.start.to_point(&display_map));
 2441                end = buffer.anchor_before(range.end.to_point(&display_map));
 2442                mode = SelectMode::Word(start..end);
 2443                auto_scroll = true;
 2444            }
 2445            3 => {
 2446                let position = display_map
 2447                    .clip_point(position, Bias::Left)
 2448                    .to_point(&display_map);
 2449                let line_start = display_map.prev_line_boundary(position).0;
 2450                let next_line_start = buffer.clip_point(
 2451                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2452                    Bias::Left,
 2453                );
 2454                start = buffer.anchor_before(line_start);
 2455                end = buffer.anchor_before(next_line_start);
 2456                mode = SelectMode::Line(start..end);
 2457                auto_scroll = true;
 2458            }
 2459            _ => {
 2460                start = buffer.anchor_before(0);
 2461                end = buffer.anchor_before(buffer.len());
 2462                mode = SelectMode::All;
 2463                auto_scroll = false;
 2464            }
 2465        }
 2466
 2467        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
 2468            if !add {
 2469                s.clear_disjoint();
 2470            } else if click_count > 1 {
 2471                s.delete(newest_selection.id)
 2472            }
 2473
 2474            s.set_pending_anchor_range(start..end, mode);
 2475        });
 2476    }
 2477
 2478    fn begin_columnar_selection(
 2479        &mut self,
 2480        position: DisplayPoint,
 2481        goal_column: u32,
 2482        reset: bool,
 2483        cx: &mut ViewContext<Self>,
 2484    ) {
 2485        if !self.focus_handle.is_focused(cx) {
 2486            cx.focus(&self.focus_handle);
 2487        }
 2488
 2489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2490
 2491        if reset {
 2492            let pointer_position = display_map
 2493                .buffer_snapshot
 2494                .anchor_before(position.to_point(&display_map));
 2495
 2496            self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 2497                s.clear_disjoint();
 2498                s.set_pending_anchor_range(
 2499                    pointer_position..pointer_position,
 2500                    SelectMode::Character,
 2501                );
 2502            });
 2503        }
 2504
 2505        let tail = self.selections.newest::<Point>(cx).tail();
 2506        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2507
 2508        if !reset {
 2509            self.select_columns(
 2510                tail.to_display_point(&display_map),
 2511                position,
 2512                goal_column,
 2513                &display_map,
 2514                cx,
 2515            );
 2516        }
 2517    }
 2518
 2519    fn update_selection(
 2520        &mut self,
 2521        position: DisplayPoint,
 2522        goal_column: u32,
 2523        scroll_delta: gpui::Point<f32>,
 2524        cx: &mut ViewContext<Self>,
 2525    ) {
 2526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2527
 2528        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2529            let tail = tail.to_display_point(&display_map);
 2530            self.select_columns(tail, position, goal_column, &display_map, cx);
 2531        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2532            let buffer = self.buffer.read(cx).snapshot(cx);
 2533            let head;
 2534            let tail;
 2535            let mode = self.selections.pending_mode().unwrap();
 2536            match &mode {
 2537                SelectMode::Character => {
 2538                    head = position.to_point(&display_map);
 2539                    tail = pending.tail().to_point(&buffer);
 2540                }
 2541                SelectMode::Word(original_range) => {
 2542                    let original_display_range = original_range.start.to_display_point(&display_map)
 2543                        ..original_range.end.to_display_point(&display_map);
 2544                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2545                        ..original_display_range.end.to_point(&display_map);
 2546                    if movement::is_inside_word(&display_map, position)
 2547                        || original_display_range.contains(&position)
 2548                    {
 2549                        let word_range = movement::surrounding_word(&display_map, position);
 2550                        if word_range.start < original_display_range.start {
 2551                            head = word_range.start.to_point(&display_map);
 2552                        } else {
 2553                            head = word_range.end.to_point(&display_map);
 2554                        }
 2555                    } else {
 2556                        head = position.to_point(&display_map);
 2557                    }
 2558
 2559                    if head <= original_buffer_range.start {
 2560                        tail = original_buffer_range.end;
 2561                    } else {
 2562                        tail = original_buffer_range.start;
 2563                    }
 2564                }
 2565                SelectMode::Line(original_range) => {
 2566                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2567
 2568                    let position = display_map
 2569                        .clip_point(position, Bias::Left)
 2570                        .to_point(&display_map);
 2571                    let line_start = display_map.prev_line_boundary(position).0;
 2572                    let next_line_start = buffer.clip_point(
 2573                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2574                        Bias::Left,
 2575                    );
 2576
 2577                    if line_start < original_range.start {
 2578                        head = line_start
 2579                    } else {
 2580                        head = next_line_start
 2581                    }
 2582
 2583                    if head <= original_range.start {
 2584                        tail = original_range.end;
 2585                    } else {
 2586                        tail = original_range.start;
 2587                    }
 2588                }
 2589                SelectMode::All => {
 2590                    return;
 2591                }
 2592            };
 2593
 2594            if head < tail {
 2595                pending.start = buffer.anchor_before(head);
 2596                pending.end = buffer.anchor_before(tail);
 2597                pending.reversed = true;
 2598            } else {
 2599                pending.start = buffer.anchor_before(tail);
 2600                pending.end = buffer.anchor_before(head);
 2601                pending.reversed = false;
 2602            }
 2603
 2604            self.change_selections(None, cx, |s| {
 2605                s.set_pending(pending, mode);
 2606            });
 2607        } else {
 2608            log::error!("update_selection dispatched with no pending selection");
 2609            return;
 2610        }
 2611
 2612        self.apply_scroll_delta(scroll_delta, cx);
 2613        cx.notify();
 2614    }
 2615
 2616    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 2617        self.columnar_selection_tail.take();
 2618        if self.selections.pending_anchor().is_some() {
 2619            let selections = self.selections.all::<usize>(cx);
 2620            self.change_selections(None, cx, |s| {
 2621                s.select(selections);
 2622                s.clear_pending();
 2623            });
 2624        }
 2625    }
 2626
 2627    fn select_columns(
 2628        &mut self,
 2629        tail: DisplayPoint,
 2630        head: DisplayPoint,
 2631        goal_column: u32,
 2632        display_map: &DisplaySnapshot,
 2633        cx: &mut ViewContext<Self>,
 2634    ) {
 2635        let start_row = cmp::min(tail.row(), head.row());
 2636        let end_row = cmp::max(tail.row(), head.row());
 2637        let start_column = cmp::min(tail.column(), goal_column);
 2638        let end_column = cmp::max(tail.column(), goal_column);
 2639        let reversed = start_column < tail.column();
 2640
 2641        let selection_ranges = (start_row.0..=end_row.0)
 2642            .map(DisplayRow)
 2643            .filter_map(|row| {
 2644                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2645                    let start = display_map
 2646                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2647                        .to_point(display_map);
 2648                    let end = display_map
 2649                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2650                        .to_point(display_map);
 2651                    if reversed {
 2652                        Some(end..start)
 2653                    } else {
 2654                        Some(start..end)
 2655                    }
 2656                } else {
 2657                    None
 2658                }
 2659            })
 2660            .collect::<Vec<_>>();
 2661
 2662        self.change_selections(None, cx, |s| {
 2663            s.select_ranges(selection_ranges);
 2664        });
 2665        cx.notify();
 2666    }
 2667
 2668    pub fn has_pending_nonempty_selection(&self) -> bool {
 2669        let pending_nonempty_selection = match self.selections.pending_anchor() {
 2670            Some(Selection { start, end, .. }) => start != end,
 2671            None => false,
 2672        };
 2673        pending_nonempty_selection || self.columnar_selection_tail.is_some()
 2674    }
 2675
 2676    pub fn has_pending_selection(&self) -> bool {
 2677        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 2678    }
 2679
 2680    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 2681        self.clear_expanded_diff_hunks(cx);
 2682        if self.dismiss_menus_and_popups(true, cx) {
 2683            return;
 2684        }
 2685
 2686        if self.mode == EditorMode::Full {
 2687            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
 2688                return;
 2689            }
 2690        }
 2691
 2692        cx.propagate();
 2693    }
 2694
 2695    pub fn dismiss_menus_and_popups(
 2696        &mut self,
 2697        should_report_inline_completion_event: bool,
 2698        cx: &mut ViewContext<Self>,
 2699    ) -> bool {
 2700        if self.take_rename(false, cx).is_some() {
 2701            return true;
 2702        }
 2703
 2704        if hide_hover(self, cx) {
 2705            return true;
 2706        }
 2707
 2708        if self.hide_context_menu(cx).is_some() {
 2709            return true;
 2710        }
 2711
 2712        if self.discard_inline_completion(should_report_inline_completion_event, cx) {
 2713            return true;
 2714        }
 2715
 2716        if self.snippet_stack.pop().is_some() {
 2717            return true;
 2718        }
 2719
 2720        if self.mode == EditorMode::Full {
 2721            if self.active_diagnostics.is_some() {
 2722                self.dismiss_diagnostics(cx);
 2723                return true;
 2724            }
 2725        }
 2726
 2727        false
 2728    }
 2729
 2730    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2731        let text: Arc<str> = text.into();
 2732
 2733        if self.read_only(cx) {
 2734            return;
 2735        }
 2736
 2737        let selections = self.selections.all_adjusted(cx);
 2738        let mut brace_inserted = false;
 2739        let mut edits = Vec::new();
 2740        let mut new_selections = Vec::with_capacity(selections.len());
 2741        let mut new_autoclose_regions = Vec::new();
 2742        let snapshot = self.buffer.read(cx).read(cx);
 2743
 2744        for (selection, autoclose_region) in
 2745            self.selections_with_autoclose_regions(selections, &snapshot)
 2746        {
 2747            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 2748                // Determine if the inserted text matches the opening or closing
 2749                // bracket of any of this language's bracket pairs.
 2750                let mut bracket_pair = None;
 2751                let mut is_bracket_pair_start = false;
 2752                let mut is_bracket_pair_end = false;
 2753                if !text.is_empty() {
 2754                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 2755                    //  and they are removing the character that triggered IME popup.
 2756                    for (pair, enabled) in scope.brackets() {
 2757                        if !pair.close {
 2758                            continue;
 2759                        }
 2760
 2761                        if enabled && pair.start.ends_with(text.as_ref()) {
 2762                            bracket_pair = Some(pair.clone());
 2763                            is_bracket_pair_start = true;
 2764                            break;
 2765                        }
 2766                        if pair.end.as_str() == text.as_ref() {
 2767                            bracket_pair = Some(pair.clone());
 2768                            is_bracket_pair_end = true;
 2769                            break;
 2770                        }
 2771                    }
 2772                }
 2773
 2774                if let Some(bracket_pair) = bracket_pair {
 2775                    if selection.is_empty() {
 2776                        if is_bracket_pair_start {
 2777                            let prefix_len = bracket_pair.start.len() - text.len();
 2778
 2779                            // If the inserted text is a suffix of an opening bracket and the
 2780                            // selection is preceded by the rest of the opening bracket, then
 2781                            // insert the closing bracket.
 2782                            let following_text_allows_autoclose = snapshot
 2783                                .chars_at(selection.start)
 2784                                .next()
 2785                                .map_or(true, |c| scope.should_autoclose_before(c));
 2786                            let preceding_text_matches_prefix = prefix_len == 0
 2787                                || (selection.start.column >= (prefix_len as u32)
 2788                                    && snapshot.contains_str_at(
 2789                                        Point::new(
 2790                                            selection.start.row,
 2791                                            selection.start.column - (prefix_len as u32),
 2792                                        ),
 2793                                        &bracket_pair.start[..prefix_len],
 2794                                    ));
 2795                            let autoclose = self.use_autoclose
 2796                                && snapshot.settings_at(selection.start, cx).use_autoclose;
 2797                            if autoclose
 2798                                && following_text_allows_autoclose
 2799                                && preceding_text_matches_prefix
 2800                            {
 2801                                let anchor = snapshot.anchor_before(selection.end);
 2802                                new_selections.push((selection.map(|_| anchor), text.len()));
 2803                                new_autoclose_regions.push((
 2804                                    anchor,
 2805                                    text.len(),
 2806                                    selection.id,
 2807                                    bracket_pair.clone(),
 2808                                ));
 2809                                edits.push((
 2810                                    selection.range(),
 2811                                    format!("{}{}", text, bracket_pair.end).into(),
 2812                                ));
 2813                                brace_inserted = true;
 2814                                continue;
 2815                            }
 2816                        }
 2817
 2818                        if let Some(region) = autoclose_region {
 2819                            // If the selection is followed by an auto-inserted closing bracket,
 2820                            // then don't insert that closing bracket again; just move the selection
 2821                            // past the closing bracket.
 2822                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 2823                                && text.as_ref() == region.pair.end.as_str();
 2824                            if should_skip {
 2825                                let anchor = snapshot.anchor_after(selection.end);
 2826                                new_selections
 2827                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 2828                                continue;
 2829                            }
 2830                        }
 2831
 2832                        let always_treat_brackets_as_autoclosed = snapshot
 2833                            .settings_at(selection.start, cx)
 2834                            .always_treat_brackets_as_autoclosed;
 2835                        if always_treat_brackets_as_autoclosed
 2836                            && is_bracket_pair_end
 2837                            && snapshot.contains_str_at(selection.end, text.as_ref())
 2838                        {
 2839                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 2840                            // and the inserted text is a closing bracket and the selection is followed
 2841                            // by the closing bracket then move the selection past the closing bracket.
 2842                            let anchor = snapshot.anchor_after(selection.end);
 2843                            new_selections.push((selection.map(|_| anchor), text.len()));
 2844                            continue;
 2845                        }
 2846                    }
 2847                    // If an opening bracket is 1 character long and is typed while
 2848                    // text is selected, then surround that text with the bracket pair.
 2849                    else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
 2850                        edits.push((selection.start..selection.start, text.clone()));
 2851                        edits.push((
 2852                            selection.end..selection.end,
 2853                            bracket_pair.end.as_str().into(),
 2854                        ));
 2855                        brace_inserted = true;
 2856                        new_selections.push((
 2857                            Selection {
 2858                                id: selection.id,
 2859                                start: snapshot.anchor_after(selection.start),
 2860                                end: snapshot.anchor_before(selection.end),
 2861                                reversed: selection.reversed,
 2862                                goal: selection.goal,
 2863                            },
 2864                            0,
 2865                        ));
 2866                        continue;
 2867                    }
 2868                }
 2869            }
 2870
 2871            if self.auto_replace_emoji_shortcode
 2872                && selection.is_empty()
 2873                && text.as_ref().ends_with(':')
 2874            {
 2875                if let Some(possible_emoji_short_code) =
 2876                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 2877                {
 2878                    if !possible_emoji_short_code.is_empty() {
 2879                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 2880                            let emoji_shortcode_start = Point::new(
 2881                                selection.start.row,
 2882                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 2883                            );
 2884
 2885                            // Remove shortcode from buffer
 2886                            edits.push((
 2887                                emoji_shortcode_start..selection.start,
 2888                                "".to_string().into(),
 2889                            ));
 2890                            new_selections.push((
 2891                                Selection {
 2892                                    id: selection.id,
 2893                                    start: snapshot.anchor_after(emoji_shortcode_start),
 2894                                    end: snapshot.anchor_before(selection.start),
 2895                                    reversed: selection.reversed,
 2896                                    goal: selection.goal,
 2897                                },
 2898                                0,
 2899                            ));
 2900
 2901                            // Insert emoji
 2902                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 2903                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 2904                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 2905
 2906                            continue;
 2907                        }
 2908                    }
 2909                }
 2910            }
 2911
 2912            // If not handling any auto-close operation, then just replace the selected
 2913            // text with the given input and move the selection to the end of the
 2914            // newly inserted text.
 2915            let anchor = snapshot.anchor_after(selection.end);
 2916            new_selections.push((selection.map(|_| anchor), 0));
 2917            edits.push((selection.start..selection.end, text.clone()));
 2918        }
 2919
 2920        drop(snapshot);
 2921        self.transact(cx, |this, cx| {
 2922            this.buffer.update(cx, |buffer, cx| {
 2923                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 2924            });
 2925
 2926            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 2927            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 2928            let snapshot = this.buffer.read(cx).read(cx);
 2929            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
 2930                .zip(new_selection_deltas)
 2931                .map(|(selection, delta)| Selection {
 2932                    id: selection.id,
 2933                    start: selection.start + delta,
 2934                    end: selection.end + delta,
 2935                    reversed: selection.reversed,
 2936                    goal: SelectionGoal::None,
 2937                })
 2938                .collect::<Vec<_>>();
 2939
 2940            let mut i = 0;
 2941            for (position, delta, selection_id, pair) in new_autoclose_regions {
 2942                let position = position.to_offset(&snapshot) + delta;
 2943                let start = snapshot.anchor_before(position);
 2944                let end = snapshot.anchor_after(position);
 2945                while let Some(existing_state) = this.autoclose_regions.get(i) {
 2946                    match existing_state.range.start.cmp(&start, &snapshot) {
 2947                        Ordering::Less => i += 1,
 2948                        Ordering::Greater => break,
 2949                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
 2950                            Ordering::Less => i += 1,
 2951                            Ordering::Equal => break,
 2952                            Ordering::Greater => break,
 2953                        },
 2954                    }
 2955                }
 2956                this.autoclose_regions.insert(
 2957                    i,
 2958                    AutocloseRegion {
 2959                        selection_id,
 2960                        range: start..end,
 2961                        pair,
 2962                    },
 2963                );
 2964            }
 2965
 2966            drop(snapshot);
 2967            let had_active_inline_completion = this.has_active_inline_completion(cx);
 2968            this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| {
 2969                s.select(new_selections)
 2970            });
 2971
 2972            if brace_inserted {
 2973                // If we inserted a brace while composing text (i.e. typing `"` on a
 2974                // Brazilian keyboard), exit the composing state because most likely
 2975                // the user wanted to surround the selection.
 2976                this.unmark_text(cx);
 2977            } else if EditorSettings::get_global(cx).use_on_type_format {
 2978                if let Some(on_type_format_task) =
 2979                    this.trigger_on_type_formatting(text.to_string(), cx)
 2980                {
 2981                    on_type_format_task.detach_and_log_err(cx);
 2982                }
 2983            }
 2984
 2985            let trigger_in_words = !had_active_inline_completion;
 2986            this.trigger_completion_on_input(&text, trigger_in_words, cx);
 2987            this.refresh_inline_completion(true, cx);
 2988        });
 2989    }
 2990
 2991    fn find_possible_emoji_shortcode_at_position(
 2992        snapshot: &MultiBufferSnapshot,
 2993        position: Point,
 2994    ) -> Option<String> {
 2995        let mut chars = Vec::new();
 2996        let mut found_colon = false;
 2997        for char in snapshot.reversed_chars_at(position).take(100) {
 2998            // Found a possible emoji shortcode in the middle of the buffer
 2999            if found_colon {
 3000                if char.is_whitespace() {
 3001                    chars.reverse();
 3002                    return Some(chars.iter().collect());
 3003                }
 3004                // If the previous character is not a whitespace, we are in the middle of a word
 3005                // and we only want to complete the shortcode if the word is made up of other emojis
 3006                let mut containing_word = String::new();
 3007                for ch in snapshot
 3008                    .reversed_chars_at(position)
 3009                    .skip(chars.len() + 1)
 3010                    .take(100)
 3011                {
 3012                    if ch.is_whitespace() {
 3013                        break;
 3014                    }
 3015                    containing_word.push(ch);
 3016                }
 3017                let containing_word = containing_word.chars().rev().collect::<String>();
 3018                if util::word_consists_of_emojis(containing_word.as_str()) {
 3019                    chars.reverse();
 3020                    return Some(chars.iter().collect());
 3021                }
 3022            }
 3023
 3024            if char.is_whitespace() || !char.is_ascii() {
 3025                return None;
 3026            }
 3027            if char == ':' {
 3028                found_colon = true;
 3029            } else {
 3030                chars.push(char);
 3031            }
 3032        }
 3033        // Found a possible emoji shortcode at the beginning of the buffer
 3034        chars.reverse();
 3035        Some(chars.iter().collect())
 3036    }
 3037
 3038    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 3039        self.transact(cx, |this, cx| {
 3040            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3041                let selections = this.selections.all::<usize>(cx);
 3042                let multi_buffer = this.buffer.read(cx);
 3043                let buffer = multi_buffer.snapshot(cx);
 3044                selections
 3045                    .iter()
 3046                    .map(|selection| {
 3047                        let start_point = selection.start.to_point(&buffer);
 3048                        let mut indent =
 3049                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3050                        indent.len = cmp::min(indent.len, start_point.column);
 3051                        let start = selection.start;
 3052                        let end = selection.end;
 3053                        let selection_is_empty = start == end;
 3054                        let language_scope = buffer.language_scope_at(start);
 3055                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3056                            &language_scope
 3057                        {
 3058                            let leading_whitespace_len = buffer
 3059                                .reversed_chars_at(start)
 3060                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3061                                .map(|c| c.len_utf8())
 3062                                .sum::<usize>();
 3063
 3064                            let trailing_whitespace_len = buffer
 3065                                .chars_at(end)
 3066                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3067                                .map(|c| c.len_utf8())
 3068                                .sum::<usize>();
 3069
 3070                            let insert_extra_newline =
 3071                                language.brackets().any(|(pair, enabled)| {
 3072                                    let pair_start = pair.start.trim_end();
 3073                                    let pair_end = pair.end.trim_start();
 3074
 3075                                    enabled
 3076                                        && pair.newline
 3077                                        && buffer.contains_str_at(
 3078                                            end + trailing_whitespace_len,
 3079                                            pair_end,
 3080                                        )
 3081                                        && buffer.contains_str_at(
 3082                                            (start - leading_whitespace_len)
 3083                                                .saturating_sub(pair_start.len()),
 3084                                            pair_start,
 3085                                        )
 3086                                });
 3087
 3088                            // Comment extension on newline is allowed only for cursor selections
 3089                            let comment_delimiter = maybe!({
 3090                                if !selection_is_empty {
 3091                                    return None;
 3092                                }
 3093
 3094                                if !multi_buffer.settings_at(0, cx).extend_comment_on_newline {
 3095                                    return None;
 3096                                }
 3097
 3098                                let delimiters = language.line_comment_prefixes();
 3099                                let max_len_of_delimiter =
 3100                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3101                                let (snapshot, range) =
 3102                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3103
 3104                                let mut index_of_first_non_whitespace = 0;
 3105                                let comment_candidate = snapshot
 3106                                    .chars_for_range(range)
 3107                                    .skip_while(|c| {
 3108                                        let should_skip = c.is_whitespace();
 3109                                        if should_skip {
 3110                                            index_of_first_non_whitespace += 1;
 3111                                        }
 3112                                        should_skip
 3113                                    })
 3114                                    .take(max_len_of_delimiter)
 3115                                    .collect::<String>();
 3116                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3117                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3118                                })?;
 3119                                let cursor_is_placed_after_comment_marker =
 3120                                    index_of_first_non_whitespace + comment_prefix.len()
 3121                                        <= start_point.column as usize;
 3122                                if cursor_is_placed_after_comment_marker {
 3123                                    Some(comment_prefix.clone())
 3124                                } else {
 3125                                    None
 3126                                }
 3127                            });
 3128                            (comment_delimiter, insert_extra_newline)
 3129                        } else {
 3130                            (None, false)
 3131                        };
 3132
 3133                        let capacity_for_delimiter = comment_delimiter
 3134                            .as_deref()
 3135                            .map(str::len)
 3136                            .unwrap_or_default();
 3137                        let mut new_text =
 3138                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3139                        new_text.push_str("\n");
 3140                        new_text.extend(indent.chars());
 3141                        if let Some(delimiter) = &comment_delimiter {
 3142                            new_text.push_str(&delimiter);
 3143                        }
 3144                        if insert_extra_newline {
 3145                            new_text = new_text.repeat(2);
 3146                        }
 3147
 3148                        let anchor = buffer.anchor_after(end);
 3149                        let new_selection = selection.map(|_| anchor);
 3150                        (
 3151                            (start..end, new_text),
 3152                            (insert_extra_newline, new_selection),
 3153                        )
 3154                    })
 3155                    .unzip()
 3156            };
 3157
 3158            this.edit_with_autoindent(edits, cx);
 3159            let buffer = this.buffer.read(cx).snapshot(cx);
 3160            let new_selections = selection_fixup_info
 3161                .into_iter()
 3162                .map(|(extra_newline_inserted, new_selection)| {
 3163                    let mut cursor = new_selection.end.to_point(&buffer);
 3164                    if extra_newline_inserted {
 3165                        cursor.row -= 1;
 3166                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3167                    }
 3168                    new_selection.map(|_| cursor)
 3169                })
 3170                .collect();
 3171
 3172            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 3173            this.refresh_inline_completion(true, cx);
 3174        });
 3175    }
 3176
 3177    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
 3178        let buffer = self.buffer.read(cx);
 3179        let snapshot = buffer.snapshot(cx);
 3180
 3181        let mut edits = Vec::new();
 3182        let mut rows = Vec::new();
 3183
 3184        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3185            let cursor = selection.head();
 3186            let row = cursor.row;
 3187
 3188            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3189
 3190            let newline = "\n".to_string();
 3191            edits.push((start_of_line..start_of_line, newline));
 3192
 3193            rows.push(row + rows_inserted as u32);
 3194        }
 3195
 3196        self.transact(cx, |editor, cx| {
 3197            editor.edit(edits, cx);
 3198
 3199            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3200                let mut index = 0;
 3201                s.move_cursors_with(|map, _, _| {
 3202                    let row = rows[index];
 3203                    index += 1;
 3204
 3205                    let point = Point::new(row, 0);
 3206                    let boundary = map.next_line_boundary(point).1;
 3207                    let clipped = map.clip_point(boundary, Bias::Left);
 3208
 3209                    (clipped, SelectionGoal::None)
 3210                });
 3211            });
 3212
 3213            let mut indent_edits = Vec::new();
 3214            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3215            for row in rows {
 3216                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3217                for (row, indent) in indents {
 3218                    if indent.len == 0 {
 3219                        continue;
 3220                    }
 3221
 3222                    let text = match indent.kind {
 3223                        IndentKind::Space => " ".repeat(indent.len as usize),
 3224                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3225                    };
 3226                    let point = Point::new(row.0, 0);
 3227                    indent_edits.push((point..point, text));
 3228                }
 3229            }
 3230            editor.edit(indent_edits, cx);
 3231        });
 3232    }
 3233
 3234    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
 3235        let buffer = self.buffer.read(cx);
 3236        let snapshot = buffer.snapshot(cx);
 3237
 3238        let mut edits = Vec::new();
 3239        let mut rows = Vec::new();
 3240        let mut rows_inserted = 0;
 3241
 3242        for selection in self.selections.all_adjusted(cx) {
 3243            let cursor = selection.head();
 3244            let row = cursor.row;
 3245
 3246            let point = Point::new(row + 1, 0);
 3247            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3248
 3249            let newline = "\n".to_string();
 3250            edits.push((start_of_line..start_of_line, newline));
 3251
 3252            rows_inserted += 1;
 3253            rows.push(row + rows_inserted);
 3254        }
 3255
 3256        self.transact(cx, |editor, cx| {
 3257            editor.edit(edits, cx);
 3258
 3259            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3260                let mut index = 0;
 3261                s.move_cursors_with(|map, _, _| {
 3262                    let row = rows[index];
 3263                    index += 1;
 3264
 3265                    let point = Point::new(row, 0);
 3266                    let boundary = map.next_line_boundary(point).1;
 3267                    let clipped = map.clip_point(boundary, Bias::Left);
 3268
 3269                    (clipped, SelectionGoal::None)
 3270                });
 3271            });
 3272
 3273            let mut indent_edits = Vec::new();
 3274            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3275            for row in rows {
 3276                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3277                for (row, indent) in indents {
 3278                    if indent.len == 0 {
 3279                        continue;
 3280                    }
 3281
 3282                    let text = match indent.kind {
 3283                        IndentKind::Space => " ".repeat(indent.len as usize),
 3284                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3285                    };
 3286                    let point = Point::new(row.0, 0);
 3287                    indent_edits.push((point..point, text));
 3288                }
 3289            }
 3290            editor.edit(indent_edits, cx);
 3291        });
 3292    }
 3293
 3294    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 3295        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3296            original_indent_columns: Vec::new(),
 3297        });
 3298        self.insert_with_autoindent_mode(text, autoindent, cx);
 3299    }
 3300
 3301    fn insert_with_autoindent_mode(
 3302        &mut self,
 3303        text: &str,
 3304        autoindent_mode: Option<AutoindentMode>,
 3305        cx: &mut ViewContext<Self>,
 3306    ) {
 3307        if self.read_only(cx) {
 3308            return;
 3309        }
 3310
 3311        let text: Arc<str> = text.into();
 3312        self.transact(cx, |this, cx| {
 3313            let old_selections = this.selections.all_adjusted(cx);
 3314            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3315                let anchors = {
 3316                    let snapshot = buffer.read(cx);
 3317                    old_selections
 3318                        .iter()
 3319                        .map(|s| {
 3320                            let anchor = snapshot.anchor_after(s.head());
 3321                            s.map(|_| anchor)
 3322                        })
 3323                        .collect::<Vec<_>>()
 3324                };
 3325                buffer.edit(
 3326                    old_selections
 3327                        .iter()
 3328                        .map(|s| (s.start..s.end, text.clone())),
 3329                    autoindent_mode,
 3330                    cx,
 3331                );
 3332                anchors
 3333            });
 3334
 3335            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3336                s.select_anchors(selection_anchors);
 3337            })
 3338        });
 3339    }
 3340
 3341    fn trigger_completion_on_input(
 3342        &mut self,
 3343        text: &str,
 3344        trigger_in_words: bool,
 3345        cx: &mut ViewContext<Self>,
 3346    ) {
 3347        if self.is_completion_trigger(text, trigger_in_words, cx) {
 3348            self.show_completions(&ShowCompletions, cx);
 3349        } else {
 3350            self.hide_context_menu(cx);
 3351        }
 3352    }
 3353
 3354    fn is_completion_trigger(
 3355        &self,
 3356        text: &str,
 3357        trigger_in_words: bool,
 3358        cx: &mut ViewContext<Self>,
 3359    ) -> bool {
 3360        let position = self.selections.newest_anchor().head();
 3361        let multibuffer = self.buffer.read(cx);
 3362        let Some(buffer) = position
 3363            .buffer_id
 3364            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 3365        else {
 3366            return false;
 3367        };
 3368
 3369        if let Some(completion_provider) = &self.completion_provider {
 3370            completion_provider.is_completion_trigger(
 3371                &buffer,
 3372                position.text_anchor,
 3373                text,
 3374                trigger_in_words,
 3375                cx,
 3376            )
 3377        } else {
 3378            false
 3379        }
 3380    }
 3381
 3382    /// If any empty selections is touching the start of its innermost containing autoclose
 3383    /// region, expand it to select the brackets.
 3384    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
 3385        let selections = self.selections.all::<usize>(cx);
 3386        let buffer = self.buffer.read(cx).read(cx);
 3387        let new_selections = self
 3388            .selections_with_autoclose_regions(selections, &buffer)
 3389            .map(|(mut selection, region)| {
 3390                if !selection.is_empty() {
 3391                    return selection;
 3392                }
 3393
 3394                if let Some(region) = region {
 3395                    let mut range = region.range.to_offset(&buffer);
 3396                    if selection.start == range.start && range.start >= region.pair.start.len() {
 3397                        range.start -= region.pair.start.len();
 3398                        if buffer.contains_str_at(range.start, &region.pair.start)
 3399                            && buffer.contains_str_at(range.end, &region.pair.end)
 3400                        {
 3401                            range.end += region.pair.end.len();
 3402                            selection.start = range.start;
 3403                            selection.end = range.end;
 3404
 3405                            return selection;
 3406                        }
 3407                    }
 3408                }
 3409
 3410                let always_treat_brackets_as_autoclosed = buffer
 3411                    .settings_at(selection.start, cx)
 3412                    .always_treat_brackets_as_autoclosed;
 3413
 3414                if !always_treat_brackets_as_autoclosed {
 3415                    return selection;
 3416                }
 3417
 3418                if let Some(scope) = buffer.language_scope_at(selection.start) {
 3419                    for (pair, enabled) in scope.brackets() {
 3420                        if !enabled || !pair.close {
 3421                            continue;
 3422                        }
 3423
 3424                        if buffer.contains_str_at(selection.start, &pair.end) {
 3425                            let pair_start_len = pair.start.len();
 3426                            if buffer.contains_str_at(selection.start - pair_start_len, &pair.start)
 3427                            {
 3428                                selection.start -= pair_start_len;
 3429                                selection.end += pair.end.len();
 3430
 3431                                return selection;
 3432                            }
 3433                        }
 3434                    }
 3435                }
 3436
 3437                selection
 3438            })
 3439            .collect();
 3440
 3441        drop(buffer);
 3442        self.change_selections(None, cx, |selections| selections.select(new_selections));
 3443    }
 3444
 3445    /// Iterate the given selections, and for each one, find the smallest surrounding
 3446    /// autoclose region. This uses the ordering of the selections and the autoclose
 3447    /// regions to avoid repeated comparisons.
 3448    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 3449        &'a self,
 3450        selections: impl IntoIterator<Item = Selection<D>>,
 3451        buffer: &'a MultiBufferSnapshot,
 3452    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 3453        let mut i = 0;
 3454        let mut regions = self.autoclose_regions.as_slice();
 3455        selections.into_iter().map(move |selection| {
 3456            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 3457
 3458            let mut enclosing = None;
 3459            while let Some(pair_state) = regions.get(i) {
 3460                if pair_state.range.end.to_offset(buffer) < range.start {
 3461                    regions = &regions[i + 1..];
 3462                    i = 0;
 3463                } else if pair_state.range.start.to_offset(buffer) > range.end {
 3464                    break;
 3465                } else {
 3466                    if pair_state.selection_id == selection.id {
 3467                        enclosing = Some(pair_state);
 3468                    }
 3469                    i += 1;
 3470                }
 3471            }
 3472
 3473            (selection.clone(), enclosing)
 3474        })
 3475    }
 3476
 3477    /// Remove any autoclose regions that no longer contain their selection.
 3478    fn invalidate_autoclose_regions(
 3479        &mut self,
 3480        mut selections: &[Selection<Anchor>],
 3481        buffer: &MultiBufferSnapshot,
 3482    ) {
 3483        self.autoclose_regions.retain(|state| {
 3484            let mut i = 0;
 3485            while let Some(selection) = selections.get(i) {
 3486                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 3487                    selections = &selections[1..];
 3488                    continue;
 3489                }
 3490                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 3491                    break;
 3492                }
 3493                if selection.id == state.selection_id {
 3494                    return true;
 3495                } else {
 3496                    i += 1;
 3497                }
 3498            }
 3499            false
 3500        });
 3501    }
 3502
 3503    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 3504        let offset = position.to_offset(buffer);
 3505        let (word_range, kind) = buffer.surrounding_word(offset);
 3506        if offset > word_range.start && kind == Some(CharKind::Word) {
 3507            Some(
 3508                buffer
 3509                    .text_for_range(word_range.start..offset)
 3510                    .collect::<String>(),
 3511            )
 3512        } else {
 3513            None
 3514        }
 3515    }
 3516
 3517    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
 3518        self.refresh_inlay_hints(
 3519            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
 3520            cx,
 3521        );
 3522    }
 3523
 3524    pub fn inlay_hints_enabled(&self) -> bool {
 3525        self.inlay_hint_cache.enabled
 3526    }
 3527
 3528    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
 3529        if self.project.is_none() || self.mode != EditorMode::Full {
 3530            return;
 3531        }
 3532
 3533        let reason_description = reason.description();
 3534        let ignore_debounce = matches!(
 3535            reason,
 3536            InlayHintRefreshReason::SettingsChange(_)
 3537                | InlayHintRefreshReason::Toggle(_)
 3538                | InlayHintRefreshReason::ExcerptsRemoved(_)
 3539        );
 3540        let (invalidate_cache, required_languages) = match reason {
 3541            InlayHintRefreshReason::Toggle(enabled) => {
 3542                self.inlay_hint_cache.enabled = enabled;
 3543                if enabled {
 3544                    (InvalidationStrategy::RefreshRequested, None)
 3545                } else {
 3546                    self.inlay_hint_cache.clear();
 3547                    self.splice_inlays(
 3548                        self.visible_inlay_hints(cx)
 3549                            .iter()
 3550                            .map(|inlay| inlay.id)
 3551                            .collect(),
 3552                        Vec::new(),
 3553                        cx,
 3554                    );
 3555                    return;
 3556                }
 3557            }
 3558            InlayHintRefreshReason::SettingsChange(new_settings) => {
 3559                match self.inlay_hint_cache.update_settings(
 3560                    &self.buffer,
 3561                    new_settings,
 3562                    self.visible_inlay_hints(cx),
 3563                    cx,
 3564                ) {
 3565                    ControlFlow::Break(Some(InlaySplice {
 3566                        to_remove,
 3567                        to_insert,
 3568                    })) => {
 3569                        self.splice_inlays(to_remove, to_insert, cx);
 3570                        return;
 3571                    }
 3572                    ControlFlow::Break(None) => return,
 3573                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 3574                }
 3575            }
 3576            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 3577                if let Some(InlaySplice {
 3578                    to_remove,
 3579                    to_insert,
 3580                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 3581                {
 3582                    self.splice_inlays(to_remove, to_insert, cx);
 3583                }
 3584                return;
 3585            }
 3586            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 3587            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 3588                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 3589            }
 3590            InlayHintRefreshReason::RefreshRequested => {
 3591                (InvalidationStrategy::RefreshRequested, None)
 3592            }
 3593        };
 3594
 3595        if let Some(InlaySplice {
 3596            to_remove,
 3597            to_insert,
 3598        }) = self.inlay_hint_cache.spawn_hint_refresh(
 3599            reason_description,
 3600            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 3601            invalidate_cache,
 3602            ignore_debounce,
 3603            cx,
 3604        ) {
 3605            self.splice_inlays(to_remove, to_insert, cx);
 3606        }
 3607    }
 3608
 3609    fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
 3610        self.display_map
 3611            .read(cx)
 3612            .current_inlays()
 3613            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 3614            .cloned()
 3615            .collect()
 3616    }
 3617
 3618    pub fn excerpts_for_inlay_hints_query(
 3619        &self,
 3620        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 3621        cx: &mut ViewContext<Editor>,
 3622    ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
 3623        let Some(project) = self.project.as_ref() else {
 3624            return HashMap::default();
 3625        };
 3626        let project = project.read(cx);
 3627        let multi_buffer = self.buffer().read(cx);
 3628        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 3629        let multi_buffer_visible_start = self
 3630            .scroll_manager
 3631            .anchor()
 3632            .anchor
 3633            .to_point(&multi_buffer_snapshot);
 3634        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 3635            multi_buffer_visible_start
 3636                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 3637            Bias::Left,
 3638        );
 3639        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 3640        multi_buffer
 3641            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
 3642            .into_iter()
 3643            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 3644            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
 3645                let buffer = buffer_handle.read(cx);
 3646                let buffer_file = project::File::from_dyn(buffer.file())?;
 3647                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 3648                let worktree_entry = buffer_worktree
 3649                    .read(cx)
 3650                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 3651                if worktree_entry.is_ignored {
 3652                    return None;
 3653                }
 3654
 3655                let language = buffer.language()?;
 3656                if let Some(restrict_to_languages) = restrict_to_languages {
 3657                    if !restrict_to_languages.contains(language) {
 3658                        return None;
 3659                    }
 3660                }
 3661                Some((
 3662                    excerpt_id,
 3663                    (
 3664                        buffer_handle,
 3665                        buffer.version().clone(),
 3666                        excerpt_visible_range,
 3667                    ),
 3668                ))
 3669            })
 3670            .collect()
 3671    }
 3672
 3673    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
 3674        TextLayoutDetails {
 3675            text_system: cx.text_system().clone(),
 3676            editor_style: self.style.clone().unwrap(),
 3677            rem_size: cx.rem_size(),
 3678            scroll_anchor: self.scroll_manager.anchor(),
 3679            visible_rows: self.visible_line_count(),
 3680            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 3681        }
 3682    }
 3683
 3684    fn splice_inlays(
 3685        &self,
 3686        to_remove: Vec<InlayId>,
 3687        to_insert: Vec<Inlay>,
 3688        cx: &mut ViewContext<Self>,
 3689    ) {
 3690        self.display_map.update(cx, |display_map, cx| {
 3691            display_map.splice_inlays(to_remove, to_insert, cx);
 3692        });
 3693        cx.notify();
 3694    }
 3695
 3696    fn trigger_on_type_formatting(
 3697        &self,
 3698        input: String,
 3699        cx: &mut ViewContext<Self>,
 3700    ) -> Option<Task<Result<()>>> {
 3701        if input.len() != 1 {
 3702            return None;
 3703        }
 3704
 3705        let project = self.project.as_ref()?;
 3706        let position = self.selections.newest_anchor().head();
 3707        let (buffer, buffer_position) = self
 3708            .buffer
 3709            .read(cx)
 3710            .text_anchor_for_position(position, cx)?;
 3711
 3712        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 3713        // hence we do LSP request & edit on host side only — add formats to host's history.
 3714        let push_to_lsp_host_history = true;
 3715        // If this is not the host, append its history with new edits.
 3716        let push_to_client_history = project.read(cx).is_remote();
 3717
 3718        let on_type_formatting = project.update(cx, |project, cx| {
 3719            project.on_type_format(
 3720                buffer.clone(),
 3721                buffer_position,
 3722                input,
 3723                push_to_lsp_host_history,
 3724                cx,
 3725            )
 3726        });
 3727        Some(cx.spawn(|editor, mut cx| async move {
 3728            if let Some(transaction) = on_type_formatting.await? {
 3729                if push_to_client_history {
 3730                    buffer
 3731                        .update(&mut cx, |buffer, _| {
 3732                            buffer.push_transaction(transaction, Instant::now());
 3733                        })
 3734                        .ok();
 3735                }
 3736                editor.update(&mut cx, |editor, cx| {
 3737                    editor.refresh_document_highlights(cx);
 3738                })?;
 3739            }
 3740            Ok(())
 3741        }))
 3742    }
 3743
 3744    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
 3745        if self.pending_rename.is_some() {
 3746            return;
 3747        }
 3748
 3749        let Some(provider) = self.completion_provider.as_ref() else {
 3750            return;
 3751        };
 3752
 3753        let position = self.selections.newest_anchor().head();
 3754        let (buffer, buffer_position) =
 3755            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 3756                output
 3757            } else {
 3758                return;
 3759            };
 3760
 3761        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 3762        let completions = provider.completions(&buffer, buffer_position, cx);
 3763
 3764        let id = post_inc(&mut self.next_completion_id);
 3765        let task = cx.spawn(|this, mut cx| {
 3766            async move {
 3767                let completions = completions.await.log_err();
 3768                let menu = if let Some(completions) = completions {
 3769                    let mut menu = CompletionsMenu {
 3770                        id,
 3771                        initial_position: position,
 3772                        match_candidates: completions
 3773                            .iter()
 3774                            .enumerate()
 3775                            .map(|(id, completion)| {
 3776                                StringMatchCandidate::new(
 3777                                    id,
 3778                                    completion.label.text[completion.label.filter_range.clone()]
 3779                                        .into(),
 3780                                )
 3781                            })
 3782                            .collect(),
 3783                        buffer: buffer.clone(),
 3784                        completions: Arc::new(RwLock::new(completions.into())),
 3785                        matches: Vec::new().into(),
 3786                        selected_item: 0,
 3787                        scroll_handle: UniformListScrollHandle::new(),
 3788                        selected_completion_documentation_resolve_debounce: Arc::new(Mutex::new(
 3789                            DebouncedDelay::new(),
 3790                        )),
 3791                    };
 3792                    menu.filter(query.as_deref(), cx.background_executor().clone())
 3793                        .await;
 3794
 3795                    if menu.matches.is_empty() {
 3796                        None
 3797                    } else {
 3798                        this.update(&mut cx, |editor, cx| {
 3799                            let completions = menu.completions.clone();
 3800                            let matches = menu.matches.clone();
 3801
 3802                            let delay_ms = EditorSettings::get_global(cx)
 3803                                .completion_documentation_secondary_query_debounce;
 3804                            let delay = Duration::from_millis(delay_ms);
 3805
 3806                            editor
 3807                                .completion_documentation_pre_resolve_debounce
 3808                                .fire_new(delay, cx, |editor, cx| {
 3809                                    CompletionsMenu::pre_resolve_completion_documentation(
 3810                                        buffer,
 3811                                        completions,
 3812                                        matches,
 3813                                        editor,
 3814                                        cx,
 3815                                    )
 3816                                });
 3817                        })
 3818                        .ok();
 3819                        Some(menu)
 3820                    }
 3821                } else {
 3822                    None
 3823                };
 3824
 3825                this.update(&mut cx, |this, cx| {
 3826                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 3827
 3828                    let mut context_menu = this.context_menu.write();
 3829                    match context_menu.as_ref() {
 3830                        None => {}
 3831
 3832                        Some(ContextMenu::Completions(prev_menu)) => {
 3833                            if prev_menu.id > id {
 3834                                return;
 3835                            }
 3836                        }
 3837
 3838                        _ => return,
 3839                    }
 3840
 3841                    if this.focus_handle.is_focused(cx) && menu.is_some() {
 3842                        let menu = menu.unwrap();
 3843                        *context_menu = Some(ContextMenu::Completions(menu));
 3844                        drop(context_menu);
 3845                        this.discard_inline_completion(false, cx);
 3846                        cx.notify();
 3847                    } else if this.completion_tasks.len() <= 1 {
 3848                        // If there are no more completion tasks and the last menu was
 3849                        // empty, we should hide it. If it was already hidden, we should
 3850                        // also show the copilot completion when available.
 3851                        drop(context_menu);
 3852                        if this.hide_context_menu(cx).is_none() {
 3853                            this.update_visible_inline_completion(cx);
 3854                        }
 3855                    }
 3856                })?;
 3857
 3858                Ok::<_, anyhow::Error>(())
 3859            }
 3860            .log_err()
 3861        });
 3862
 3863        self.completion_tasks.push((id, task));
 3864    }
 3865
 3866    pub fn confirm_completion(
 3867        &mut self,
 3868        action: &ConfirmCompletion,
 3869        cx: &mut ViewContext<Self>,
 3870    ) -> Option<Task<Result<()>>> {
 3871        use language::ToOffset as _;
 3872
 3873        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
 3874            menu
 3875        } else {
 3876            return None;
 3877        };
 3878
 3879        let mat = completions_menu
 3880            .matches
 3881            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
 3882        let buffer_handle = completions_menu.buffer;
 3883        let completions = completions_menu.completions.read();
 3884        let completion = completions.get(mat.candidate_id)?;
 3885        cx.stop_propagation();
 3886
 3887        let snippet;
 3888        let text;
 3889        if completion.is_snippet() {
 3890            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 3891            text = snippet.as_ref().unwrap().text.clone();
 3892        } else {
 3893            snippet = None;
 3894            text = completion.new_text.clone();
 3895        };
 3896        let selections = self.selections.all::<usize>(cx);
 3897        let buffer = buffer_handle.read(cx);
 3898        let old_range = completion.old_range.to_offset(buffer);
 3899        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 3900
 3901        let newest_selection = self.selections.newest_anchor();
 3902        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
 3903            return None;
 3904        }
 3905
 3906        let lookbehind = newest_selection
 3907            .start
 3908            .text_anchor
 3909            .to_offset(buffer)
 3910            .saturating_sub(old_range.start);
 3911        let lookahead = old_range
 3912            .end
 3913            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 3914        let mut common_prefix_len = old_text
 3915            .bytes()
 3916            .zip(text.bytes())
 3917            .take_while(|(a, b)| a == b)
 3918            .count();
 3919
 3920        let snapshot = self.buffer.read(cx).snapshot(cx);
 3921        let mut range_to_replace: Option<Range<isize>> = None;
 3922        let mut ranges = Vec::new();
 3923        for selection in &selections {
 3924            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 3925                let start = selection.start.saturating_sub(lookbehind);
 3926                let end = selection.end + lookahead;
 3927                if selection.id == newest_selection.id {
 3928                    range_to_replace = Some(
 3929                        ((start + common_prefix_len) as isize - selection.start as isize)
 3930                            ..(end as isize - selection.start as isize),
 3931                    );
 3932                }
 3933                ranges.push(start + common_prefix_len..end);
 3934            } else {
 3935                common_prefix_len = 0;
 3936                ranges.clear();
 3937                ranges.extend(selections.iter().map(|s| {
 3938                    if s.id == newest_selection.id {
 3939                        range_to_replace = Some(
 3940                            old_range.start.to_offset_utf16(&snapshot).0 as isize
 3941                                - selection.start as isize
 3942                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
 3943                                    - selection.start as isize,
 3944                        );
 3945                        old_range.clone()
 3946                    } else {
 3947                        s.start..s.end
 3948                    }
 3949                }));
 3950                break;
 3951            }
 3952        }
 3953        let text = &text[common_prefix_len..];
 3954
 3955        cx.emit(EditorEvent::InputHandled {
 3956            utf16_range_to_replace: range_to_replace,
 3957            text: text.into(),
 3958        });
 3959
 3960        self.transact(cx, |this, cx| {
 3961            if let Some(mut snippet) = snippet {
 3962                snippet.text = text.to_string();
 3963                for tabstop in snippet.tabstops.iter_mut().flatten() {
 3964                    tabstop.start -= common_prefix_len as isize;
 3965                    tabstop.end -= common_prefix_len as isize;
 3966                }
 3967
 3968                this.insert_snippet(&ranges, snippet, cx).log_err();
 3969            } else {
 3970                this.buffer.update(cx, |buffer, cx| {
 3971                    buffer.edit(
 3972                        ranges.iter().map(|range| (range.clone(), text)),
 3973                        this.autoindent_mode.clone(),
 3974                        cx,
 3975                    );
 3976                });
 3977            }
 3978
 3979            this.refresh_inline_completion(true, cx);
 3980        });
 3981
 3982        let provider = self.completion_provider.as_ref()?;
 3983        let apply_edits = provider.apply_additional_edits_for_completion(
 3984            buffer_handle,
 3985            completion.clone(),
 3986            true,
 3987            cx,
 3988        );
 3989        Some(cx.foreground_executor().spawn(async move {
 3990            apply_edits.await?;
 3991            Ok(())
 3992        }))
 3993    }
 3994
 3995    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
 3996        let mut context_menu = self.context_menu.write();
 3997        if let Some(ContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 3998            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 3999                // Toggle if we're selecting the same one
 4000                *context_menu = None;
 4001                cx.notify();
 4002                return;
 4003            } else {
 4004                // Otherwise, clear it and start a new one
 4005                *context_menu = None;
 4006                cx.notify();
 4007            }
 4008        }
 4009        drop(context_menu);
 4010        let snapshot = self.snapshot(cx);
 4011        let deployed_from_indicator = action.deployed_from_indicator;
 4012        let mut task = self.code_actions_task.take();
 4013        let action = action.clone();
 4014        cx.spawn(|editor, mut cx| async move {
 4015            while let Some(prev_task) = task {
 4016                prev_task.await;
 4017                task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?;
 4018            }
 4019
 4020            let spawned_test_task = editor.update(&mut cx, |editor, cx| {
 4021                if editor.focus_handle.is_focused(cx) {
 4022                    let multibuffer_point = action
 4023                        .deployed_from_indicator
 4024                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4025                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 4026                    let (buffer, buffer_row) = snapshot
 4027                        .buffer_snapshot
 4028                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4029                        .and_then(|(buffer_snapshot, range)| {
 4030                            editor
 4031                                .buffer
 4032                                .read(cx)
 4033                                .buffer(buffer_snapshot.remote_id())
 4034                                .map(|buffer| (buffer, range.start.row))
 4035                        })?;
 4036                    let (_, code_actions) = editor
 4037                        .available_code_actions
 4038                        .clone()
 4039                        .and_then(|(location, code_actions)| {
 4040                            let snapshot = location.buffer.read(cx).snapshot();
 4041                            let point_range = location.range.to_point(&snapshot);
 4042                            let point_range = point_range.start.row..=point_range.end.row;
 4043                            if point_range.contains(&buffer_row) {
 4044                                Some((location, code_actions))
 4045                            } else {
 4046                                None
 4047                            }
 4048                        })
 4049                        .unzip();
 4050                    let buffer_id = buffer.read(cx).remote_id();
 4051                    let tasks = editor
 4052                        .tasks
 4053                        .get(&(buffer_id, buffer_row))
 4054                        .map(|t| Arc::new(t.to_owned()));
 4055                    if tasks.is_none() && code_actions.is_none() {
 4056                        return None;
 4057                    }
 4058
 4059                    editor.completion_tasks.clear();
 4060                    editor.discard_inline_completion(false, cx);
 4061                    let task_context =
 4062                        tasks
 4063                            .as_ref()
 4064                            .zip(editor.project.clone())
 4065                            .map(|(tasks, project)| {
 4066                                let position = Point::new(buffer_row, tasks.column);
 4067                                let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 4068                                let location = Location {
 4069                                    buffer: buffer.clone(),
 4070                                    range: range_start..range_start,
 4071                                };
 4072                                // Fill in the environmental variables from the tree-sitter captures
 4073                                let mut captured_task_variables = TaskVariables::default();
 4074                                for (capture_name, value) in tasks.extra_variables.clone() {
 4075                                    captured_task_variables.insert(
 4076                                        task::VariableName::Custom(capture_name.into()),
 4077                                        value.clone(),
 4078                                    );
 4079                                }
 4080                                project.update(cx, |project, cx| {
 4081                                    project.task_context_for_location(
 4082                                        captured_task_variables,
 4083                                        location,
 4084                                        cx,
 4085                                    )
 4086                                })
 4087                            });
 4088
 4089                    Some(cx.spawn(|editor, mut cx| async move {
 4090                        let task_context = match task_context {
 4091                            Some(task_context) => task_context.await,
 4092                            None => None,
 4093                        };
 4094                        let resolved_tasks =
 4095                            tasks.zip(task_context).map(|(tasks, task_context)| {
 4096                                Arc::new(ResolvedTasks {
 4097                                    templates: tasks
 4098                                        .templates
 4099                                        .iter()
 4100                                        .filter_map(|(kind, template)| {
 4101                                            template
 4102                                                .resolve_task(&kind.to_id_base(), &task_context)
 4103                                                .map(|task| (kind.clone(), task))
 4104                                        })
 4105                                        .collect(),
 4106                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 4107                                        multibuffer_point.row,
 4108                                        tasks.column,
 4109                                    )),
 4110                                })
 4111                            });
 4112                        let spawn_straight_away = resolved_tasks
 4113                            .as_ref()
 4114                            .map_or(false, |tasks| tasks.templates.len() == 1)
 4115                            && code_actions
 4116                                .as_ref()
 4117                                .map_or(true, |actions| actions.is_empty());
 4118                        if let Some(task) = editor
 4119                            .update(&mut cx, |editor, cx| {
 4120                                *editor.context_menu.write() =
 4121                                    Some(ContextMenu::CodeActions(CodeActionsMenu {
 4122                                        buffer,
 4123                                        actions: CodeActionContents {
 4124                                            tasks: resolved_tasks,
 4125                                            actions: code_actions,
 4126                                        },
 4127                                        selected_item: Default::default(),
 4128                                        scroll_handle: UniformListScrollHandle::default(),
 4129                                        deployed_from_indicator,
 4130                                    }));
 4131                                if spawn_straight_away {
 4132                                    if let Some(task) = editor.confirm_code_action(
 4133                                        &ConfirmCodeAction { item_ix: Some(0) },
 4134                                        cx,
 4135                                    ) {
 4136                                        cx.notify();
 4137                                        return task;
 4138                                    }
 4139                                }
 4140                                cx.notify();
 4141                                Task::ready(Ok(()))
 4142                            })
 4143                            .ok()
 4144                        {
 4145                            task.await
 4146                        } else {
 4147                            Ok(())
 4148                        }
 4149                    }))
 4150                } else {
 4151                    Some(Task::ready(Ok(())))
 4152                }
 4153            })?;
 4154            if let Some(task) = spawned_test_task {
 4155                task.await?;
 4156            }
 4157
 4158            Ok::<_, anyhow::Error>(())
 4159        })
 4160        .detach_and_log_err(cx);
 4161    }
 4162
 4163    pub fn confirm_code_action(
 4164        &mut self,
 4165        action: &ConfirmCodeAction,
 4166        cx: &mut ViewContext<Self>,
 4167    ) -> Option<Task<Result<()>>> {
 4168        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
 4169            menu
 4170        } else {
 4171            return None;
 4172        };
 4173        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 4174        let action = actions_menu.actions.get(action_ix)?;
 4175        let title = action.label();
 4176        let buffer = actions_menu.buffer;
 4177        let workspace = self.workspace()?;
 4178
 4179        match action {
 4180            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 4181                workspace.update(cx, |workspace, cx| {
 4182                    workspace::tasks::schedule_resolved_task(
 4183                        workspace,
 4184                        task_source_kind,
 4185                        resolved_task,
 4186                        false,
 4187                        cx,
 4188                    );
 4189
 4190                    Some(Task::ready(Ok(())))
 4191                })
 4192            }
 4193            CodeActionsItem::CodeAction(action) => {
 4194                let apply_code_actions = workspace
 4195                    .read(cx)
 4196                    .project()
 4197                    .clone()
 4198                    .update(cx, |project, cx| {
 4199                        project.apply_code_action(buffer, action, true, cx)
 4200                    });
 4201                let workspace = workspace.downgrade();
 4202                Some(cx.spawn(|editor, cx| async move {
 4203                    let project_transaction = apply_code_actions.await?;
 4204                    Self::open_project_transaction(
 4205                        &editor,
 4206                        workspace,
 4207                        project_transaction,
 4208                        title,
 4209                        cx,
 4210                    )
 4211                    .await
 4212                }))
 4213            }
 4214        }
 4215    }
 4216
 4217    pub async fn open_project_transaction(
 4218        this: &WeakView<Editor>,
 4219        workspace: WeakView<Workspace>,
 4220        transaction: ProjectTransaction,
 4221        title: String,
 4222        mut cx: AsyncWindowContext,
 4223    ) -> Result<()> {
 4224        let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
 4225
 4226        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 4227        cx.update(|cx| {
 4228            entries.sort_unstable_by_key(|(buffer, _)| {
 4229                buffer.read(cx).file().map(|f| f.path().clone())
 4230            });
 4231        })?;
 4232
 4233        // If the project transaction's edits are all contained within this editor, then
 4234        // avoid opening a new editor to display them.
 4235
 4236        if let Some((buffer, transaction)) = entries.first() {
 4237            if entries.len() == 1 {
 4238                let excerpt = this.update(&mut cx, |editor, cx| {
 4239                    editor
 4240                        .buffer()
 4241                        .read(cx)
 4242                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 4243                })?;
 4244                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 4245                    if excerpted_buffer == *buffer {
 4246                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
 4247                            let excerpt_range = excerpt_range.to_offset(buffer);
 4248                            buffer
 4249                                .edited_ranges_for_transaction::<usize>(transaction)
 4250                                .all(|range| {
 4251                                    excerpt_range.start <= range.start
 4252                                        && excerpt_range.end >= range.end
 4253                                })
 4254                        })?;
 4255
 4256                        if all_edits_within_excerpt {
 4257                            return Ok(());
 4258                        }
 4259                    }
 4260                }
 4261            }
 4262        } else {
 4263            return Ok(());
 4264        }
 4265
 4266        let mut ranges_to_highlight = Vec::new();
 4267        let excerpt_buffer = cx.new_model(|cx| {
 4268            let mut multibuffer =
 4269                MultiBuffer::new(replica_id, Capability::ReadWrite).with_title(title);
 4270            for (buffer_handle, transaction) in &entries {
 4271                let buffer = buffer_handle.read(cx);
 4272                ranges_to_highlight.extend(
 4273                    multibuffer.push_excerpts_with_context_lines(
 4274                        buffer_handle.clone(),
 4275                        buffer
 4276                            .edited_ranges_for_transaction::<usize>(transaction)
 4277                            .collect(),
 4278                        DEFAULT_MULTIBUFFER_CONTEXT,
 4279                        cx,
 4280                    ),
 4281                );
 4282            }
 4283            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 4284            multibuffer
 4285        })?;
 4286
 4287        workspace.update(&mut cx, |workspace, cx| {
 4288            let project = workspace.project().clone();
 4289            let editor =
 4290                cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
 4291            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, cx);
 4292            editor.update(cx, |editor, cx| {
 4293                editor.highlight_background::<Self>(
 4294                    &ranges_to_highlight,
 4295                    |theme| theme.editor_highlighted_line_background,
 4296                    cx,
 4297                );
 4298            });
 4299        })?;
 4300
 4301        Ok(())
 4302    }
 4303
 4304    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 4305        let project = self.project.clone()?;
 4306        let buffer = self.buffer.read(cx);
 4307        let newest_selection = self.selections.newest_anchor().clone();
 4308        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 4309        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 4310        if start_buffer != end_buffer {
 4311            return None;
 4312        }
 4313
 4314        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
 4315            cx.background_executor()
 4316                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 4317                .await;
 4318
 4319            let actions = if let Ok(code_actions) = project.update(&mut cx, |project, cx| {
 4320                project.code_actions(&start_buffer, start..end, cx)
 4321            }) {
 4322                code_actions.await
 4323            } else {
 4324                Vec::new()
 4325            };
 4326
 4327            this.update(&mut cx, |this, cx| {
 4328                this.available_code_actions = if actions.is_empty() {
 4329                    None
 4330                } else {
 4331                    Some((
 4332                        Location {
 4333                            buffer: start_buffer,
 4334                            range: start..end,
 4335                        },
 4336                        actions.into(),
 4337                    ))
 4338                };
 4339                cx.notify();
 4340            })
 4341            .log_err();
 4342        }));
 4343        None
 4344    }
 4345
 4346    fn start_inline_blame_timer(&mut self, cx: &mut ViewContext<Self>) {
 4347        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 4348            self.show_git_blame_inline = false;
 4349
 4350            self.show_git_blame_inline_delay_task = Some(cx.spawn(|this, mut cx| async move {
 4351                cx.background_executor().timer(delay).await;
 4352
 4353                this.update(&mut cx, |this, cx| {
 4354                    this.show_git_blame_inline = true;
 4355                    cx.notify();
 4356                })
 4357                .log_err();
 4358            }));
 4359        }
 4360    }
 4361
 4362    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 4363        if self.pending_rename.is_some() {
 4364            return None;
 4365        }
 4366
 4367        let project = self.project.clone()?;
 4368        let buffer = self.buffer.read(cx);
 4369        let newest_selection = self.selections.newest_anchor().clone();
 4370        let cursor_position = newest_selection.head();
 4371        let (cursor_buffer, cursor_buffer_position) =
 4372            buffer.text_anchor_for_position(cursor_position, cx)?;
 4373        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 4374        if cursor_buffer != tail_buffer {
 4375            return None;
 4376        }
 4377
 4378        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
 4379            cx.background_executor()
 4380                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
 4381                .await;
 4382
 4383            let highlights = if let Some(highlights) = project
 4384                .update(&mut cx, |project, cx| {
 4385                    project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 4386                })
 4387                .log_err()
 4388            {
 4389                highlights.await.log_err()
 4390            } else {
 4391                None
 4392            };
 4393
 4394            if let Some(highlights) = highlights {
 4395                this.update(&mut cx, |this, cx| {
 4396                    if this.pending_rename.is_some() {
 4397                        return;
 4398                    }
 4399
 4400                    let buffer_id = cursor_position.buffer_id;
 4401                    let buffer = this.buffer.read(cx);
 4402                    if !buffer
 4403                        .text_anchor_for_position(cursor_position, cx)
 4404                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 4405                    {
 4406                        return;
 4407                    }
 4408
 4409                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 4410                    let mut write_ranges = Vec::new();
 4411                    let mut read_ranges = Vec::new();
 4412                    for highlight in highlights {
 4413                        for (excerpt_id, excerpt_range) in
 4414                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
 4415                        {
 4416                            let start = highlight
 4417                                .range
 4418                                .start
 4419                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 4420                            let end = highlight
 4421                                .range
 4422                                .end
 4423                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 4424                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 4425                                continue;
 4426                            }
 4427
 4428                            let range = Anchor {
 4429                                buffer_id,
 4430                                excerpt_id: excerpt_id,
 4431                                text_anchor: start,
 4432                            }..Anchor {
 4433                                buffer_id,
 4434                                excerpt_id,
 4435                                text_anchor: end,
 4436                            };
 4437                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 4438                                write_ranges.push(range);
 4439                            } else {
 4440                                read_ranges.push(range);
 4441                            }
 4442                        }
 4443                    }
 4444
 4445                    this.highlight_background::<DocumentHighlightRead>(
 4446                        &read_ranges,
 4447                        |theme| theme.editor_document_highlight_read_background,
 4448                        cx,
 4449                    );
 4450                    this.highlight_background::<DocumentHighlightWrite>(
 4451                        &write_ranges,
 4452                        |theme| theme.editor_document_highlight_write_background,
 4453                        cx,
 4454                    );
 4455                    cx.notify();
 4456                })
 4457                .log_err();
 4458            }
 4459        }));
 4460        None
 4461    }
 4462
 4463    fn refresh_inline_completion(
 4464        &mut self,
 4465        debounce: bool,
 4466        cx: &mut ViewContext<Self>,
 4467    ) -> Option<()> {
 4468        let provider = self.inline_completion_provider()?;
 4469        let cursor = self.selections.newest_anchor().head();
 4470        let (buffer, cursor_buffer_position) =
 4471            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 4472        if !self.show_inline_completions
 4473            || !provider.is_enabled(&buffer, cursor_buffer_position, cx)
 4474        {
 4475            self.discard_inline_completion(false, cx);
 4476            return None;
 4477        }
 4478
 4479        self.update_visible_inline_completion(cx);
 4480        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 4481        Some(())
 4482    }
 4483
 4484    fn cycle_inline_completion(
 4485        &mut self,
 4486        direction: Direction,
 4487        cx: &mut ViewContext<Self>,
 4488    ) -> Option<()> {
 4489        let provider = self.inline_completion_provider()?;
 4490        let cursor = self.selections.newest_anchor().head();
 4491        let (buffer, cursor_buffer_position) =
 4492            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 4493        if !self.show_inline_completions
 4494            || !provider.is_enabled(&buffer, cursor_buffer_position, cx)
 4495        {
 4496            return None;
 4497        }
 4498
 4499        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 4500        self.update_visible_inline_completion(cx);
 4501
 4502        Some(())
 4503    }
 4504
 4505    pub fn show_inline_completion(&mut self, _: &ShowInlineCompletion, cx: &mut ViewContext<Self>) {
 4506        if !self.has_active_inline_completion(cx) {
 4507            self.refresh_inline_completion(false, cx);
 4508            return;
 4509        }
 4510
 4511        self.update_visible_inline_completion(cx);
 4512    }
 4513
 4514    pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext<Self>) {
 4515        self.show_cursor_names(cx);
 4516    }
 4517
 4518    fn show_cursor_names(&mut self, cx: &mut ViewContext<Self>) {
 4519        self.show_cursor_names = true;
 4520        cx.notify();
 4521        cx.spawn(|this, mut cx| async move {
 4522            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 4523            this.update(&mut cx, |this, cx| {
 4524                this.show_cursor_names = false;
 4525                cx.notify()
 4526            })
 4527            .ok()
 4528        })
 4529        .detach();
 4530    }
 4531
 4532    pub fn next_inline_completion(&mut self, _: &NextInlineCompletion, cx: &mut ViewContext<Self>) {
 4533        if self.has_active_inline_completion(cx) {
 4534            self.cycle_inline_completion(Direction::Next, cx);
 4535        } else {
 4536            let is_copilot_disabled = self.refresh_inline_completion(false, cx).is_none();
 4537            if is_copilot_disabled {
 4538                cx.propagate();
 4539            }
 4540        }
 4541    }
 4542
 4543    pub fn previous_inline_completion(
 4544        &mut self,
 4545        _: &PreviousInlineCompletion,
 4546        cx: &mut ViewContext<Self>,
 4547    ) {
 4548        if self.has_active_inline_completion(cx) {
 4549            self.cycle_inline_completion(Direction::Prev, cx);
 4550        } else {
 4551            let is_copilot_disabled = self.refresh_inline_completion(false, cx).is_none();
 4552            if is_copilot_disabled {
 4553                cx.propagate();
 4554            }
 4555        }
 4556    }
 4557
 4558    pub fn accept_inline_completion(
 4559        &mut self,
 4560        _: &AcceptInlineCompletion,
 4561        cx: &mut ViewContext<Self>,
 4562    ) {
 4563        let Some(completion) = self.take_active_inline_completion(cx) else {
 4564            return;
 4565        };
 4566        if let Some(provider) = self.inline_completion_provider() {
 4567            provider.accept(cx);
 4568        }
 4569
 4570        cx.emit(EditorEvent::InputHandled {
 4571            utf16_range_to_replace: None,
 4572            text: completion.text.to_string().into(),
 4573        });
 4574        self.insert_with_autoindent_mode(&completion.text.to_string(), None, cx);
 4575        self.refresh_inline_completion(true, cx);
 4576        cx.notify();
 4577    }
 4578
 4579    pub fn accept_partial_inline_completion(
 4580        &mut self,
 4581        _: &AcceptPartialInlineCompletion,
 4582        cx: &mut ViewContext<Self>,
 4583    ) {
 4584        if self.selections.count() == 1 && self.has_active_inline_completion(cx) {
 4585            if let Some(completion) = self.take_active_inline_completion(cx) {
 4586                let mut partial_completion = completion
 4587                    .text
 4588                    .chars()
 4589                    .by_ref()
 4590                    .take_while(|c| c.is_alphabetic())
 4591                    .collect::<String>();
 4592                if partial_completion.is_empty() {
 4593                    partial_completion = completion
 4594                        .text
 4595                        .chars()
 4596                        .by_ref()
 4597                        .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 4598                        .collect::<String>();
 4599                }
 4600
 4601                cx.emit(EditorEvent::InputHandled {
 4602                    utf16_range_to_replace: None,
 4603                    text: partial_completion.clone().into(),
 4604                });
 4605                self.insert_with_autoindent_mode(&partial_completion, None, cx);
 4606                self.refresh_inline_completion(true, cx);
 4607                cx.notify();
 4608            }
 4609        }
 4610    }
 4611
 4612    fn discard_inline_completion(
 4613        &mut self,
 4614        should_report_inline_completion_event: bool,
 4615        cx: &mut ViewContext<Self>,
 4616    ) -> bool {
 4617        if let Some(provider) = self.inline_completion_provider() {
 4618            provider.discard(should_report_inline_completion_event, cx);
 4619        }
 4620
 4621        self.take_active_inline_completion(cx).is_some()
 4622    }
 4623
 4624    pub fn has_active_inline_completion(&self, cx: &AppContext) -> bool {
 4625        if let Some(completion) = self.active_inline_completion.as_ref() {
 4626            let buffer = self.buffer.read(cx).read(cx);
 4627            completion.position.is_valid(&buffer)
 4628        } else {
 4629            false
 4630        }
 4631    }
 4632
 4633    fn take_active_inline_completion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
 4634        let completion = self.active_inline_completion.take()?;
 4635        self.display_map.update(cx, |map, cx| {
 4636            map.splice_inlays(vec![completion.id], Default::default(), cx);
 4637        });
 4638        let buffer = self.buffer.read(cx).read(cx);
 4639
 4640        if completion.position.is_valid(&buffer) {
 4641            Some(completion)
 4642        } else {
 4643            None
 4644        }
 4645    }
 4646
 4647    fn update_visible_inline_completion(&mut self, cx: &mut ViewContext<Self>) {
 4648        let selection = self.selections.newest_anchor();
 4649        let cursor = selection.head();
 4650
 4651        if self.context_menu.read().is_none()
 4652            && self.completion_tasks.is_empty()
 4653            && selection.start == selection.end
 4654        {
 4655            if let Some(provider) = self.inline_completion_provider() {
 4656                if let Some((buffer, cursor_buffer_position)) =
 4657                    self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 4658                {
 4659                    if let Some(text) =
 4660                        provider.active_completion_text(&buffer, cursor_buffer_position, cx)
 4661                    {
 4662                        let text = Rope::from(text);
 4663                        let mut to_remove = Vec::new();
 4664                        if let Some(completion) = self.active_inline_completion.take() {
 4665                            to_remove.push(completion.id);
 4666                        }
 4667
 4668                        let completion_inlay =
 4669                            Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
 4670                        self.active_inline_completion = Some(completion_inlay.clone());
 4671                        self.display_map.update(cx, move |map, cx| {
 4672                            map.splice_inlays(to_remove, vec![completion_inlay], cx)
 4673                        });
 4674                        cx.notify();
 4675                        return;
 4676                    }
 4677                }
 4678            }
 4679        }
 4680
 4681        self.discard_inline_completion(false, cx);
 4682    }
 4683
 4684    fn inline_completion_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 4685        Some(self.inline_completion_provider.as_ref()?.provider.clone())
 4686    }
 4687
 4688    fn render_code_actions_indicator(
 4689        &self,
 4690        _style: &EditorStyle,
 4691        row: DisplayRow,
 4692        is_active: bool,
 4693        cx: &mut ViewContext<Self>,
 4694    ) -> Option<IconButton> {
 4695        if self.available_code_actions.is_some() {
 4696            Some(
 4697                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 4698                    .icon_size(IconSize::XSmall)
 4699                    .size(ui::ButtonSize::None)
 4700                    .icon_color(Color::Muted)
 4701                    .selected(is_active)
 4702                    .on_click(cx.listener(move |editor, _e, cx| {
 4703                        editor.focus(cx);
 4704                        editor.toggle_code_actions(
 4705                            &ToggleCodeActions {
 4706                                deployed_from_indicator: Some(row),
 4707                            },
 4708                            cx,
 4709                        );
 4710                    })),
 4711            )
 4712        } else {
 4713            None
 4714        }
 4715    }
 4716
 4717    fn clear_tasks(&mut self) {
 4718        self.tasks.clear()
 4719    }
 4720
 4721    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 4722        if let Some(_) = self.tasks.insert(key, value) {
 4723            // This case should hopefully be rare, but just in case...
 4724            log::error!("multiple different run targets found on a single line, only the last target will be rendered")
 4725        }
 4726    }
 4727
 4728    fn render_run_indicator(
 4729        &self,
 4730        _style: &EditorStyle,
 4731        is_active: bool,
 4732        row: DisplayRow,
 4733        cx: &mut ViewContext<Self>,
 4734    ) -> IconButton {
 4735        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 4736            .icon_size(IconSize::XSmall)
 4737            .size(ui::ButtonSize::None)
 4738            .icon_color(Color::Muted)
 4739            .selected(is_active)
 4740            .on_click(cx.listener(move |editor, _e, cx| {
 4741                editor.focus(cx);
 4742                editor.toggle_code_actions(
 4743                    &ToggleCodeActions {
 4744                        deployed_from_indicator: Some(row),
 4745                    },
 4746                    cx,
 4747                );
 4748            }))
 4749    }
 4750
 4751    pub fn context_menu_visible(&self) -> bool {
 4752        self.context_menu
 4753            .read()
 4754            .as_ref()
 4755            .map_or(false, |menu| menu.visible())
 4756    }
 4757
 4758    fn render_context_menu(
 4759        &self,
 4760        cursor_position: DisplayPoint,
 4761        style: &EditorStyle,
 4762        max_height: Pixels,
 4763        cx: &mut ViewContext<Editor>,
 4764    ) -> Option<(ContextMenuOrigin, AnyElement)> {
 4765        self.context_menu.read().as_ref().map(|menu| {
 4766            menu.render(
 4767                cursor_position,
 4768                style,
 4769                max_height,
 4770                self.workspace.as_ref().map(|(w, _)| w.clone()),
 4771                cx,
 4772            )
 4773        })
 4774    }
 4775
 4776    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
 4777        cx.notify();
 4778        self.completion_tasks.clear();
 4779        let context_menu = self.context_menu.write().take();
 4780        if context_menu.is_some() {
 4781            self.update_visible_inline_completion(cx);
 4782        }
 4783        context_menu
 4784    }
 4785
 4786    pub fn insert_snippet(
 4787        &mut self,
 4788        insertion_ranges: &[Range<usize>],
 4789        snippet: Snippet,
 4790        cx: &mut ViewContext<Self>,
 4791    ) -> Result<()> {
 4792        struct Tabstop<T> {
 4793            is_end_tabstop: bool,
 4794            ranges: Vec<Range<T>>,
 4795        }
 4796
 4797        let tabstops = self.buffer.update(cx, |buffer, cx| {
 4798            let snippet_text: Arc<str> = snippet.text.clone().into();
 4799            buffer.edit(
 4800                insertion_ranges
 4801                    .iter()
 4802                    .cloned()
 4803                    .map(|range| (range, snippet_text.clone())),
 4804                Some(AutoindentMode::EachLine),
 4805                cx,
 4806            );
 4807
 4808            let snapshot = &*buffer.read(cx);
 4809            let snippet = &snippet;
 4810            snippet
 4811                .tabstops
 4812                .iter()
 4813                .map(|tabstop| {
 4814                    let is_end_tabstop = tabstop.first().map_or(false, |tabstop| {
 4815                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 4816                    });
 4817                    let mut tabstop_ranges = tabstop
 4818                        .iter()
 4819                        .flat_map(|tabstop_range| {
 4820                            let mut delta = 0_isize;
 4821                            insertion_ranges.iter().map(move |insertion_range| {
 4822                                let insertion_start = insertion_range.start as isize + delta;
 4823                                delta +=
 4824                                    snippet.text.len() as isize - insertion_range.len() as isize;
 4825
 4826                                let start = ((insertion_start + tabstop_range.start) as usize)
 4827                                    .min(snapshot.len());
 4828                                let end = ((insertion_start + tabstop_range.end) as usize)
 4829                                    .min(snapshot.len());
 4830                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 4831                            })
 4832                        })
 4833                        .collect::<Vec<_>>();
 4834                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 4835
 4836                    Tabstop {
 4837                        is_end_tabstop,
 4838                        ranges: tabstop_ranges,
 4839                    }
 4840                })
 4841                .collect::<Vec<_>>()
 4842        });
 4843
 4844        if let Some(tabstop) = tabstops.first() {
 4845            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4846                s.select_ranges(tabstop.ranges.iter().cloned());
 4847            });
 4848
 4849            // If we're already at the last tabstop and it's at the end of the snippet,
 4850            // we're done, we don't need to keep the state around.
 4851            if !tabstop.is_end_tabstop {
 4852                let ranges = tabstops
 4853                    .into_iter()
 4854                    .map(|tabstop| tabstop.ranges)
 4855                    .collect::<Vec<_>>();
 4856                self.snippet_stack.push(SnippetState {
 4857                    active_index: 0,
 4858                    ranges,
 4859                });
 4860            }
 4861
 4862            // Check whether the just-entered snippet ends with an auto-closable bracket.
 4863            if self.autoclose_regions.is_empty() {
 4864                let snapshot = self.buffer.read(cx).snapshot(cx);
 4865                for selection in &mut self.selections.all::<Point>(cx) {
 4866                    let selection_head = selection.head();
 4867                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 4868                        continue;
 4869                    };
 4870
 4871                    let mut bracket_pair = None;
 4872                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 4873                    let prev_chars = snapshot
 4874                        .reversed_chars_at(selection_head)
 4875                        .collect::<String>();
 4876                    for (pair, enabled) in scope.brackets() {
 4877                        if enabled
 4878                            && pair.close
 4879                            && prev_chars.starts_with(pair.start.as_str())
 4880                            && next_chars.starts_with(pair.end.as_str())
 4881                        {
 4882                            bracket_pair = Some(pair.clone());
 4883                            break;
 4884                        }
 4885                    }
 4886                    if let Some(pair) = bracket_pair {
 4887                        let start = snapshot.anchor_after(selection_head);
 4888                        let end = snapshot.anchor_after(selection_head);
 4889                        self.autoclose_regions.push(AutocloseRegion {
 4890                            selection_id: selection.id,
 4891                            range: start..end,
 4892                            pair,
 4893                        });
 4894                    }
 4895                }
 4896            }
 4897        }
 4898        Ok(())
 4899    }
 4900
 4901    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 4902        self.move_to_snippet_tabstop(Bias::Right, cx)
 4903    }
 4904
 4905    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 4906        self.move_to_snippet_tabstop(Bias::Left, cx)
 4907    }
 4908
 4909    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
 4910        if let Some(mut snippet) = self.snippet_stack.pop() {
 4911            match bias {
 4912                Bias::Left => {
 4913                    if snippet.active_index > 0 {
 4914                        snippet.active_index -= 1;
 4915                    } else {
 4916                        self.snippet_stack.push(snippet);
 4917                        return false;
 4918                    }
 4919                }
 4920                Bias::Right => {
 4921                    if snippet.active_index + 1 < snippet.ranges.len() {
 4922                        snippet.active_index += 1;
 4923                    } else {
 4924                        self.snippet_stack.push(snippet);
 4925                        return false;
 4926                    }
 4927                }
 4928            }
 4929            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 4930                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4931                    s.select_anchor_ranges(current_ranges.iter().cloned())
 4932                });
 4933                // If snippet state is not at the last tabstop, push it back on the stack
 4934                if snippet.active_index + 1 < snippet.ranges.len() {
 4935                    self.snippet_stack.push(snippet);
 4936                }
 4937                return true;
 4938            }
 4939        }
 4940
 4941        false
 4942    }
 4943
 4944    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
 4945        self.transact(cx, |this, cx| {
 4946            this.select_all(&SelectAll, cx);
 4947            this.insert("", cx);
 4948        });
 4949    }
 4950
 4951    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
 4952        self.transact(cx, |this, cx| {
 4953            this.select_autoclose_pair(cx);
 4954            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 4955            if !this.selections.line_mode {
 4956                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4957                for selection in &mut selections {
 4958                    if selection.is_empty() {
 4959                        let old_head = selection.head();
 4960                        let mut new_head =
 4961                            movement::left(&display_map, old_head.to_display_point(&display_map))
 4962                                .to_point(&display_map);
 4963                        if let Some((buffer, line_buffer_range)) = display_map
 4964                            .buffer_snapshot
 4965                            .buffer_line_for_row(MultiBufferRow(old_head.row))
 4966                        {
 4967                            let indent_size =
 4968                                buffer.indent_size_for_line(line_buffer_range.start.row);
 4969                            let indent_len = match indent_size.kind {
 4970                                IndentKind::Space => {
 4971                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
 4972                                }
 4973                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 4974                            };
 4975                            if old_head.column <= indent_size.len && old_head.column > 0 {
 4976                                let indent_len = indent_len.get();
 4977                                new_head = cmp::min(
 4978                                    new_head,
 4979                                    MultiBufferPoint::new(
 4980                                        old_head.row,
 4981                                        ((old_head.column - 1) / indent_len) * indent_len,
 4982                                    ),
 4983                                );
 4984                            }
 4985                        }
 4986
 4987                        selection.set_head(new_head, SelectionGoal::None);
 4988                    }
 4989                }
 4990            }
 4991
 4992            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 4993            this.insert("", cx);
 4994            this.refresh_inline_completion(true, cx);
 4995        });
 4996    }
 4997
 4998    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
 4999        self.transact(cx, |this, cx| {
 5000            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5001                let line_mode = s.line_mode;
 5002                s.move_with(|map, selection| {
 5003                    if selection.is_empty() && !line_mode {
 5004                        let cursor = movement::right(map, selection.head());
 5005                        selection.end = cursor;
 5006                        selection.reversed = true;
 5007                        selection.goal = SelectionGoal::None;
 5008                    }
 5009                })
 5010            });
 5011            this.insert("", cx);
 5012            this.refresh_inline_completion(true, cx);
 5013        });
 5014    }
 5015
 5016    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
 5017        if self.move_to_prev_snippet_tabstop(cx) {
 5018            return;
 5019        }
 5020
 5021        self.outdent(&Outdent, cx);
 5022    }
 5023
 5024    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
 5025        if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) {
 5026            return;
 5027        }
 5028
 5029        let mut selections = self.selections.all_adjusted(cx);
 5030        let buffer = self.buffer.read(cx);
 5031        let snapshot = buffer.snapshot(cx);
 5032        let rows_iter = selections.iter().map(|s| s.head().row);
 5033        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 5034
 5035        let mut edits = Vec::new();
 5036        let mut prev_edited_row = 0;
 5037        let mut row_delta = 0;
 5038        for selection in &mut selections {
 5039            if selection.start.row != prev_edited_row {
 5040                row_delta = 0;
 5041            }
 5042            prev_edited_row = selection.end.row;
 5043
 5044            // If the selection is non-empty, then increase the indentation of the selected lines.
 5045            if !selection.is_empty() {
 5046                row_delta =
 5047                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 5048                continue;
 5049            }
 5050
 5051            // If the selection is empty and the cursor is in the leading whitespace before the
 5052            // suggested indentation, then auto-indent the line.
 5053            let cursor = selection.head();
 5054            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 5055            if let Some(suggested_indent) =
 5056                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 5057            {
 5058                if cursor.column < suggested_indent.len
 5059                    && cursor.column <= current_indent.len
 5060                    && current_indent.len <= suggested_indent.len
 5061                {
 5062                    selection.start = Point::new(cursor.row, suggested_indent.len);
 5063                    selection.end = selection.start;
 5064                    if row_delta == 0 {
 5065                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 5066                            cursor.row,
 5067                            current_indent,
 5068                            suggested_indent,
 5069                        ));
 5070                        row_delta = suggested_indent.len - current_indent.len;
 5071                    }
 5072                    continue;
 5073                }
 5074            }
 5075
 5076            // Otherwise, insert a hard or soft tab.
 5077            let settings = buffer.settings_at(cursor, cx);
 5078            let tab_size = if settings.hard_tabs {
 5079                IndentSize::tab()
 5080            } else {
 5081                let tab_size = settings.tab_size.get();
 5082                let char_column = snapshot
 5083                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 5084                    .flat_map(str::chars)
 5085                    .count()
 5086                    + row_delta as usize;
 5087                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 5088                IndentSize::spaces(chars_to_next_tab_stop)
 5089            };
 5090            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 5091            selection.end = selection.start;
 5092            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 5093            row_delta += tab_size.len;
 5094        }
 5095
 5096        self.transact(cx, |this, cx| {
 5097            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 5098            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5099            this.refresh_inline_completion(true, cx);
 5100        });
 5101    }
 5102
 5103    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
 5104        if self.read_only(cx) {
 5105            return;
 5106        }
 5107        let mut selections = self.selections.all::<Point>(cx);
 5108        let mut prev_edited_row = 0;
 5109        let mut row_delta = 0;
 5110        let mut edits = Vec::new();
 5111        let buffer = self.buffer.read(cx);
 5112        let snapshot = buffer.snapshot(cx);
 5113        for selection in &mut selections {
 5114            if selection.start.row != prev_edited_row {
 5115                row_delta = 0;
 5116            }
 5117            prev_edited_row = selection.end.row;
 5118
 5119            row_delta =
 5120                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 5121        }
 5122
 5123        self.transact(cx, |this, cx| {
 5124            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 5125            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5126        });
 5127    }
 5128
 5129    fn indent_selection(
 5130        buffer: &MultiBuffer,
 5131        snapshot: &MultiBufferSnapshot,
 5132        selection: &mut Selection<Point>,
 5133        edits: &mut Vec<(Range<Point>, String)>,
 5134        delta_for_start_row: u32,
 5135        cx: &AppContext,
 5136    ) -> u32 {
 5137        let settings = buffer.settings_at(selection.start, cx);
 5138        let tab_size = settings.tab_size.get();
 5139        let indent_kind = if settings.hard_tabs {
 5140            IndentKind::Tab
 5141        } else {
 5142            IndentKind::Space
 5143        };
 5144        let mut start_row = selection.start.row;
 5145        let mut end_row = selection.end.row + 1;
 5146
 5147        // If a selection ends at the beginning of a line, don't indent
 5148        // that last line.
 5149        if selection.end.column == 0 && selection.end.row > selection.start.row {
 5150            end_row -= 1;
 5151        }
 5152
 5153        // Avoid re-indenting a row that has already been indented by a
 5154        // previous selection, but still update this selection's column
 5155        // to reflect that indentation.
 5156        if delta_for_start_row > 0 {
 5157            start_row += 1;
 5158            selection.start.column += delta_for_start_row;
 5159            if selection.end.row == selection.start.row {
 5160                selection.end.column += delta_for_start_row;
 5161            }
 5162        }
 5163
 5164        let mut delta_for_end_row = 0;
 5165        let has_multiple_rows = start_row + 1 != end_row;
 5166        for row in start_row..end_row {
 5167            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 5168            let indent_delta = match (current_indent.kind, indent_kind) {
 5169                (IndentKind::Space, IndentKind::Space) => {
 5170                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 5171                    IndentSize::spaces(columns_to_next_tab_stop)
 5172                }
 5173                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 5174                (_, IndentKind::Tab) => IndentSize::tab(),
 5175            };
 5176
 5177            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 5178                0
 5179            } else {
 5180                selection.start.column
 5181            };
 5182            let row_start = Point::new(row, start);
 5183            edits.push((
 5184                row_start..row_start,
 5185                indent_delta.chars().collect::<String>(),
 5186            ));
 5187
 5188            // Update this selection's endpoints to reflect the indentation.
 5189            if row == selection.start.row {
 5190                selection.start.column += indent_delta.len;
 5191            }
 5192            if row == selection.end.row {
 5193                selection.end.column += indent_delta.len;
 5194                delta_for_end_row = indent_delta.len;
 5195            }
 5196        }
 5197
 5198        if selection.start.row == selection.end.row {
 5199            delta_for_start_row + delta_for_end_row
 5200        } else {
 5201            delta_for_end_row
 5202        }
 5203    }
 5204
 5205    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
 5206        if self.read_only(cx) {
 5207            return;
 5208        }
 5209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5210        let selections = self.selections.all::<Point>(cx);
 5211        let mut deletion_ranges = Vec::new();
 5212        let mut last_outdent = None;
 5213        {
 5214            let buffer = self.buffer.read(cx);
 5215            let snapshot = buffer.snapshot(cx);
 5216            for selection in &selections {
 5217                let settings = buffer.settings_at(selection.start, cx);
 5218                let tab_size = settings.tab_size.get();
 5219                let mut rows = selection.spanned_rows(false, &display_map);
 5220
 5221                // Avoid re-outdenting a row that has already been outdented by a
 5222                // previous selection.
 5223                if let Some(last_row) = last_outdent {
 5224                    if last_row == rows.start {
 5225                        rows.start = rows.start.next_row();
 5226                    }
 5227                }
 5228                let has_multiple_rows = rows.len() > 1;
 5229                for row in rows.iter_rows() {
 5230                    let indent_size = snapshot.indent_size_for_line(row);
 5231                    if indent_size.len > 0 {
 5232                        let deletion_len = match indent_size.kind {
 5233                            IndentKind::Space => {
 5234                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 5235                                if columns_to_prev_tab_stop == 0 {
 5236                                    tab_size
 5237                                } else {
 5238                                    columns_to_prev_tab_stop
 5239                                }
 5240                            }
 5241                            IndentKind::Tab => 1,
 5242                        };
 5243                        let start = if has_multiple_rows
 5244                            || deletion_len > selection.start.column
 5245                            || indent_size.len < selection.start.column
 5246                        {
 5247                            0
 5248                        } else {
 5249                            selection.start.column - deletion_len
 5250                        };
 5251                        deletion_ranges.push(
 5252                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 5253                        );
 5254                        last_outdent = Some(row);
 5255                    }
 5256                }
 5257            }
 5258        }
 5259
 5260        self.transact(cx, |this, cx| {
 5261            this.buffer.update(cx, |buffer, cx| {
 5262                let empty_str: Arc<str> = "".into();
 5263                buffer.edit(
 5264                    deletion_ranges
 5265                        .into_iter()
 5266                        .map(|range| (range, empty_str.clone())),
 5267                    None,
 5268                    cx,
 5269                );
 5270            });
 5271            let selections = this.selections.all::<usize>(cx);
 5272            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5273        });
 5274    }
 5275
 5276    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
 5277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5278        let selections = self.selections.all::<Point>(cx);
 5279
 5280        let mut new_cursors = Vec::new();
 5281        let mut edit_ranges = Vec::new();
 5282        let mut selections = selections.iter().peekable();
 5283        while let Some(selection) = selections.next() {
 5284            let mut rows = selection.spanned_rows(false, &display_map);
 5285            let goal_display_column = selection.head().to_display_point(&display_map).column();
 5286
 5287            // Accumulate contiguous regions of rows that we want to delete.
 5288            while let Some(next_selection) = selections.peek() {
 5289                let next_rows = next_selection.spanned_rows(false, &display_map);
 5290                if next_rows.start <= rows.end {
 5291                    rows.end = next_rows.end;
 5292                    selections.next().unwrap();
 5293                } else {
 5294                    break;
 5295                }
 5296            }
 5297
 5298            let buffer = &display_map.buffer_snapshot;
 5299            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 5300            let edit_end;
 5301            let cursor_buffer_row;
 5302            if buffer.max_point().row >= rows.end.0 {
 5303                // If there's a line after the range, delete the \n from the end of the row range
 5304                // and position the cursor on the next line.
 5305                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 5306                cursor_buffer_row = rows.end;
 5307            } else {
 5308                // If there isn't a line after the range, delete the \n from the line before the
 5309                // start of the row range and position the cursor there.
 5310                edit_start = edit_start.saturating_sub(1);
 5311                edit_end = buffer.len();
 5312                cursor_buffer_row = rows.start.previous_row();
 5313            }
 5314
 5315            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 5316            *cursor.column_mut() =
 5317                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 5318
 5319            new_cursors.push((
 5320                selection.id,
 5321                buffer.anchor_after(cursor.to_point(&display_map)),
 5322            ));
 5323            edit_ranges.push(edit_start..edit_end);
 5324        }
 5325
 5326        self.transact(cx, |this, cx| {
 5327            let buffer = this.buffer.update(cx, |buffer, cx| {
 5328                let empty_str: Arc<str> = "".into();
 5329                buffer.edit(
 5330                    edit_ranges
 5331                        .into_iter()
 5332                        .map(|range| (range, empty_str.clone())),
 5333                    None,
 5334                    cx,
 5335                );
 5336                buffer.snapshot(cx)
 5337            });
 5338            let new_selections = new_cursors
 5339                .into_iter()
 5340                .map(|(id, cursor)| {
 5341                    let cursor = cursor.to_point(&buffer);
 5342                    Selection {
 5343                        id,
 5344                        start: cursor,
 5345                        end: cursor,
 5346                        reversed: false,
 5347                        goal: SelectionGoal::None,
 5348                    }
 5349                })
 5350                .collect();
 5351
 5352            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5353                s.select(new_selections);
 5354            });
 5355        });
 5356    }
 5357
 5358    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
 5359        if self.read_only(cx) {
 5360            return;
 5361        }
 5362        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 5363        for selection in self.selections.all::<Point>(cx) {
 5364            let start = MultiBufferRow(selection.start.row);
 5365            let end = if selection.start.row == selection.end.row {
 5366                MultiBufferRow(selection.start.row + 1)
 5367            } else {
 5368                MultiBufferRow(selection.end.row)
 5369            };
 5370
 5371            if let Some(last_row_range) = row_ranges.last_mut() {
 5372                if start <= last_row_range.end {
 5373                    last_row_range.end = end;
 5374                    continue;
 5375                }
 5376            }
 5377            row_ranges.push(start..end);
 5378        }
 5379
 5380        let snapshot = self.buffer.read(cx).snapshot(cx);
 5381        let mut cursor_positions = Vec::new();
 5382        for row_range in &row_ranges {
 5383            let anchor = snapshot.anchor_before(Point::new(
 5384                row_range.end.previous_row().0,
 5385                snapshot.line_len(row_range.end.previous_row()),
 5386            ));
 5387            cursor_positions.push(anchor..anchor);
 5388        }
 5389
 5390        self.transact(cx, |this, cx| {
 5391            for row_range in row_ranges.into_iter().rev() {
 5392                for row in row_range.iter_rows().rev() {
 5393                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 5394                    let next_line_row = row.next_row();
 5395                    let indent = snapshot.indent_size_for_line(next_line_row);
 5396                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 5397
 5398                    let replace = if snapshot.line_len(next_line_row) > indent.len {
 5399                        " "
 5400                    } else {
 5401                        ""
 5402                    };
 5403
 5404                    this.buffer.update(cx, |buffer, cx| {
 5405                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 5406                    });
 5407                }
 5408            }
 5409
 5410            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5411                s.select_anchor_ranges(cursor_positions)
 5412            });
 5413        });
 5414    }
 5415
 5416    pub fn sort_lines_case_sensitive(
 5417        &mut self,
 5418        _: &SortLinesCaseSensitive,
 5419        cx: &mut ViewContext<Self>,
 5420    ) {
 5421        self.manipulate_lines(cx, |lines| lines.sort())
 5422    }
 5423
 5424    pub fn sort_lines_case_insensitive(
 5425        &mut self,
 5426        _: &SortLinesCaseInsensitive,
 5427        cx: &mut ViewContext<Self>,
 5428    ) {
 5429        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
 5430    }
 5431
 5432    pub fn unique_lines_case_insensitive(
 5433        &mut self,
 5434        _: &UniqueLinesCaseInsensitive,
 5435        cx: &mut ViewContext<Self>,
 5436    ) {
 5437        self.manipulate_lines(cx, |lines| {
 5438            let mut seen = HashSet::default();
 5439            lines.retain(|line| seen.insert(line.to_lowercase()));
 5440        })
 5441    }
 5442
 5443    pub fn unique_lines_case_sensitive(
 5444        &mut self,
 5445        _: &UniqueLinesCaseSensitive,
 5446        cx: &mut ViewContext<Self>,
 5447    ) {
 5448        self.manipulate_lines(cx, |lines| {
 5449            let mut seen = HashSet::default();
 5450            lines.retain(|line| seen.insert(*line));
 5451        })
 5452    }
 5453
 5454    pub fn revert_selected_hunks(&mut self, _: &RevertSelectedHunks, cx: &mut ViewContext<Self>) {
 5455        let revert_changes = self.gather_revert_changes(&self.selections.disjoint_anchors(), cx);
 5456        if !revert_changes.is_empty() {
 5457            self.transact(cx, |editor, cx| {
 5458                editor.buffer().update(cx, |multi_buffer, cx| {
 5459                    for (buffer_id, changes) in revert_changes {
 5460                        if let Some(buffer) = multi_buffer.buffer(buffer_id) {
 5461                            buffer.update(cx, |buffer, cx| {
 5462                                buffer.edit(
 5463                                    changes.into_iter().map(|(range, text)| {
 5464                                        (range, text.to_string().map(Arc::<str>::from))
 5465                                    }),
 5466                                    None,
 5467                                    cx,
 5468                                );
 5469                            });
 5470                        }
 5471                    }
 5472                });
 5473                editor.change_selections(None, cx, |selections| selections.refresh());
 5474            });
 5475        }
 5476    }
 5477
 5478    pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
 5479        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 5480            let project_path = buffer.read(cx).project_path(cx)?;
 5481            let project = self.project.as_ref()?.read(cx);
 5482            let entry = project.entry_for_path(&project_path, cx)?;
 5483            let abs_path = project.absolute_path(&project_path, cx)?;
 5484            let parent = if entry.is_symlink {
 5485                abs_path.canonicalize().ok()?
 5486            } else {
 5487                abs_path
 5488            }
 5489            .parent()?
 5490            .to_path_buf();
 5491            Some(parent)
 5492        }) {
 5493            cx.dispatch_action(OpenTerminal { working_directory }.boxed_clone());
 5494        }
 5495    }
 5496
 5497    fn gather_revert_changes(
 5498        &mut self,
 5499        selections: &[Selection<Anchor>],
 5500        cx: &mut ViewContext<'_, Editor>,
 5501    ) -> HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>> {
 5502        let mut revert_changes = HashMap::default();
 5503        self.buffer.update(cx, |multi_buffer, cx| {
 5504            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5505            for hunk in hunks_for_selections(&multi_buffer_snapshot, selections) {
 5506                Self::prepare_revert_change(&mut revert_changes, &multi_buffer, &hunk, cx);
 5507            }
 5508        });
 5509        revert_changes
 5510    }
 5511
 5512    fn prepare_revert_change(
 5513        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 5514        multi_buffer: &MultiBuffer,
 5515        hunk: &DiffHunk<MultiBufferRow>,
 5516        cx: &mut AppContext,
 5517    ) -> Option<()> {
 5518        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
 5519        let buffer = buffer.read(cx);
 5520        let original_text = buffer.diff_base()?.slice(hunk.diff_base_byte_range.clone());
 5521        let buffer_snapshot = buffer.snapshot();
 5522        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 5523        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 5524            probe
 5525                .0
 5526                .start
 5527                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 5528                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 5529        }) {
 5530            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 5531            Some(())
 5532        } else {
 5533            None
 5534        }
 5535    }
 5536
 5537    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
 5538        self.manipulate_lines(cx, |lines| lines.reverse())
 5539    }
 5540
 5541    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
 5542        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
 5543    }
 5544
 5545    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 5546    where
 5547        Fn: FnMut(&mut Vec<&str>),
 5548    {
 5549        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5550        let buffer = self.buffer.read(cx).snapshot(cx);
 5551
 5552        let mut edits = Vec::new();
 5553
 5554        let selections = self.selections.all::<Point>(cx);
 5555        let mut selections = selections.iter().peekable();
 5556        let mut contiguous_row_selections = Vec::new();
 5557        let mut new_selections = Vec::new();
 5558        let mut added_lines = 0;
 5559        let mut removed_lines = 0;
 5560
 5561        while let Some(selection) = selections.next() {
 5562            let (start_row, end_row) = consume_contiguous_rows(
 5563                &mut contiguous_row_selections,
 5564                selection,
 5565                &display_map,
 5566                &mut selections,
 5567            );
 5568
 5569            let start_point = Point::new(start_row.0, 0);
 5570            let end_point = Point::new(
 5571                end_row.previous_row().0,
 5572                buffer.line_len(end_row.previous_row()),
 5573            );
 5574            let text = buffer
 5575                .text_for_range(start_point..end_point)
 5576                .collect::<String>();
 5577
 5578            let mut lines = text.split('\n').collect_vec();
 5579
 5580            let lines_before = lines.len();
 5581            callback(&mut lines);
 5582            let lines_after = lines.len();
 5583
 5584            edits.push((start_point..end_point, lines.join("\n")));
 5585
 5586            // Selections must change based on added and removed line count
 5587            let start_row =
 5588                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 5589            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 5590            new_selections.push(Selection {
 5591                id: selection.id,
 5592                start: start_row,
 5593                end: end_row,
 5594                goal: SelectionGoal::None,
 5595                reversed: selection.reversed,
 5596            });
 5597
 5598            if lines_after > lines_before {
 5599                added_lines += lines_after - lines_before;
 5600            } else if lines_before > lines_after {
 5601                removed_lines += lines_before - lines_after;
 5602            }
 5603        }
 5604
 5605        self.transact(cx, |this, cx| {
 5606            let buffer = this.buffer.update(cx, |buffer, cx| {
 5607                buffer.edit(edits, None, cx);
 5608                buffer.snapshot(cx)
 5609            });
 5610
 5611            // Recalculate offsets on newly edited buffer
 5612            let new_selections = new_selections
 5613                .iter()
 5614                .map(|s| {
 5615                    let start_point = Point::new(s.start.0, 0);
 5616                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 5617                    Selection {
 5618                        id: s.id,
 5619                        start: buffer.point_to_offset(start_point),
 5620                        end: buffer.point_to_offset(end_point),
 5621                        goal: s.goal,
 5622                        reversed: s.reversed,
 5623                    }
 5624                })
 5625                .collect();
 5626
 5627            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5628                s.select(new_selections);
 5629            });
 5630
 5631            this.request_autoscroll(Autoscroll::fit(), cx);
 5632        });
 5633    }
 5634
 5635    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
 5636        self.manipulate_text(cx, |text| text.to_uppercase())
 5637    }
 5638
 5639    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
 5640        self.manipulate_text(cx, |text| text.to_lowercase())
 5641    }
 5642
 5643    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
 5644        self.manipulate_text(cx, |text| {
 5645            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 5646            // https://github.com/rutrum/convert-case/issues/16
 5647            text.split('\n')
 5648                .map(|line| line.to_case(Case::Title))
 5649                .join("\n")
 5650        })
 5651    }
 5652
 5653    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
 5654        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
 5655    }
 5656
 5657    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
 5658        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
 5659    }
 5660
 5661    pub fn convert_to_upper_camel_case(
 5662        &mut self,
 5663        _: &ConvertToUpperCamelCase,
 5664        cx: &mut ViewContext<Self>,
 5665    ) {
 5666        self.manipulate_text(cx, |text| {
 5667            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 5668            // https://github.com/rutrum/convert-case/issues/16
 5669            text.split('\n')
 5670                .map(|line| line.to_case(Case::UpperCamel))
 5671                .join("\n")
 5672        })
 5673    }
 5674
 5675    pub fn convert_to_lower_camel_case(
 5676        &mut self,
 5677        _: &ConvertToLowerCamelCase,
 5678        cx: &mut ViewContext<Self>,
 5679    ) {
 5680        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
 5681    }
 5682
 5683    pub fn convert_to_opposite_case(
 5684        &mut self,
 5685        _: &ConvertToOppositeCase,
 5686        cx: &mut ViewContext<Self>,
 5687    ) {
 5688        self.manipulate_text(cx, |text| {
 5689            text.chars()
 5690                .fold(String::with_capacity(text.len()), |mut t, c| {
 5691                    if c.is_uppercase() {
 5692                        t.extend(c.to_lowercase());
 5693                    } else {
 5694                        t.extend(c.to_uppercase());
 5695                    }
 5696                    t
 5697                })
 5698        })
 5699    }
 5700
 5701    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 5702    where
 5703        Fn: FnMut(&str) -> String,
 5704    {
 5705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5706        let buffer = self.buffer.read(cx).snapshot(cx);
 5707
 5708        let mut new_selections = Vec::new();
 5709        let mut edits = Vec::new();
 5710        let mut selection_adjustment = 0i32;
 5711
 5712        for selection in self.selections.all::<usize>(cx) {
 5713            let selection_is_empty = selection.is_empty();
 5714
 5715            let (start, end) = if selection_is_empty {
 5716                let word_range = movement::surrounding_word(
 5717                    &display_map,
 5718                    selection.start.to_display_point(&display_map),
 5719                );
 5720                let start = word_range.start.to_offset(&display_map, Bias::Left);
 5721                let end = word_range.end.to_offset(&display_map, Bias::Left);
 5722                (start, end)
 5723            } else {
 5724                (selection.start, selection.end)
 5725            };
 5726
 5727            let text = buffer.text_for_range(start..end).collect::<String>();
 5728            let old_length = text.len() as i32;
 5729            let text = callback(&text);
 5730
 5731            new_selections.push(Selection {
 5732                start: (start as i32 - selection_adjustment) as usize,
 5733                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 5734                goal: SelectionGoal::None,
 5735                ..selection
 5736            });
 5737
 5738            selection_adjustment += old_length - text.len() as i32;
 5739
 5740            edits.push((start..end, text));
 5741        }
 5742
 5743        self.transact(cx, |this, cx| {
 5744            this.buffer.update(cx, |buffer, cx| {
 5745                buffer.edit(edits, None, cx);
 5746            });
 5747
 5748            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5749                s.select(new_selections);
 5750            });
 5751
 5752            this.request_autoscroll(Autoscroll::fit(), cx);
 5753        });
 5754    }
 5755
 5756    pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext<Self>) {
 5757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5758        let buffer = &display_map.buffer_snapshot;
 5759        let selections = self.selections.all::<Point>(cx);
 5760
 5761        let mut edits = Vec::new();
 5762        let mut selections_iter = selections.iter().peekable();
 5763        while let Some(selection) = selections_iter.next() {
 5764            // Avoid duplicating the same lines twice.
 5765            let mut rows = selection.spanned_rows(false, &display_map);
 5766
 5767            while let Some(next_selection) = selections_iter.peek() {
 5768                let next_rows = next_selection.spanned_rows(false, &display_map);
 5769                if next_rows.start < rows.end {
 5770                    rows.end = next_rows.end;
 5771                    selections_iter.next().unwrap();
 5772                } else {
 5773                    break;
 5774                }
 5775            }
 5776
 5777            // Copy the text from the selected row region and splice it either at the start
 5778            // or end of the region.
 5779            let start = Point::new(rows.start.0, 0);
 5780            let end = Point::new(
 5781                rows.end.previous_row().0,
 5782                buffer.line_len(rows.end.previous_row()),
 5783            );
 5784            let text = buffer
 5785                .text_for_range(start..end)
 5786                .chain(Some("\n"))
 5787                .collect::<String>();
 5788            let insert_location = if upwards {
 5789                Point::new(rows.end.0, 0)
 5790            } else {
 5791                start
 5792            };
 5793            edits.push((insert_location..insert_location, text));
 5794        }
 5795
 5796        self.transact(cx, |this, cx| {
 5797            this.buffer.update(cx, |buffer, cx| {
 5798                buffer.edit(edits, None, cx);
 5799            });
 5800
 5801            this.request_autoscroll(Autoscroll::fit(), cx);
 5802        });
 5803    }
 5804
 5805    pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext<Self>) {
 5806        self.duplicate_line(true, cx);
 5807    }
 5808
 5809    pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext<Self>) {
 5810        self.duplicate_line(false, cx);
 5811    }
 5812
 5813    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
 5814        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5815        let buffer = self.buffer.read(cx).snapshot(cx);
 5816
 5817        let mut edits = Vec::new();
 5818        let mut unfold_ranges = Vec::new();
 5819        let mut refold_ranges = Vec::new();
 5820
 5821        let selections = self.selections.all::<Point>(cx);
 5822        let mut selections = selections.iter().peekable();
 5823        let mut contiguous_row_selections = Vec::new();
 5824        let mut new_selections = Vec::new();
 5825
 5826        while let Some(selection) = selections.next() {
 5827            // Find all the selections that span a contiguous row range
 5828            let (start_row, end_row) = consume_contiguous_rows(
 5829                &mut contiguous_row_selections,
 5830                selection,
 5831                &display_map,
 5832                &mut selections,
 5833            );
 5834
 5835            // Move the text spanned by the row range to be before the line preceding the row range
 5836            if start_row.0 > 0 {
 5837                let range_to_move = Point::new(
 5838                    start_row.previous_row().0,
 5839                    buffer.line_len(start_row.previous_row()),
 5840                )
 5841                    ..Point::new(
 5842                        end_row.previous_row().0,
 5843                        buffer.line_len(end_row.previous_row()),
 5844                    );
 5845                let insertion_point = display_map
 5846                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 5847                    .0;
 5848
 5849                // Don't move lines across excerpts
 5850                if buffer
 5851                    .excerpt_boundaries_in_range((
 5852                        Bound::Excluded(insertion_point),
 5853                        Bound::Included(range_to_move.end),
 5854                    ))
 5855                    .next()
 5856                    .is_none()
 5857                {
 5858                    let text = buffer
 5859                        .text_for_range(range_to_move.clone())
 5860                        .flat_map(|s| s.chars())
 5861                        .skip(1)
 5862                        .chain(['\n'])
 5863                        .collect::<String>();
 5864
 5865                    edits.push((
 5866                        buffer.anchor_after(range_to_move.start)
 5867                            ..buffer.anchor_before(range_to_move.end),
 5868                        String::new(),
 5869                    ));
 5870                    let insertion_anchor = buffer.anchor_after(insertion_point);
 5871                    edits.push((insertion_anchor..insertion_anchor, text));
 5872
 5873                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 5874
 5875                    // Move selections up
 5876                    new_selections.extend(contiguous_row_selections.drain(..).map(
 5877                        |mut selection| {
 5878                            selection.start.row -= row_delta;
 5879                            selection.end.row -= row_delta;
 5880                            selection
 5881                        },
 5882                    ));
 5883
 5884                    // Move folds up
 5885                    unfold_ranges.push(range_to_move.clone());
 5886                    for fold in display_map.folds_in_range(
 5887                        buffer.anchor_before(range_to_move.start)
 5888                            ..buffer.anchor_after(range_to_move.end),
 5889                    ) {
 5890                        let mut start = fold.range.start.to_point(&buffer);
 5891                        let mut end = fold.range.end.to_point(&buffer);
 5892                        start.row -= row_delta;
 5893                        end.row -= row_delta;
 5894                        refold_ranges.push((start..end, fold.placeholder.clone()));
 5895                    }
 5896                }
 5897            }
 5898
 5899            // If we didn't move line(s), preserve the existing selections
 5900            new_selections.append(&mut contiguous_row_selections);
 5901        }
 5902
 5903        self.transact(cx, |this, cx| {
 5904            this.unfold_ranges(unfold_ranges, true, true, cx);
 5905            this.buffer.update(cx, |buffer, cx| {
 5906                for (range, text) in edits {
 5907                    buffer.edit([(range, text)], None, cx);
 5908                }
 5909            });
 5910            this.fold_ranges(refold_ranges, true, cx);
 5911            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5912                s.select(new_selections);
 5913            })
 5914        });
 5915    }
 5916
 5917    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
 5918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5919        let buffer = self.buffer.read(cx).snapshot(cx);
 5920
 5921        let mut edits = Vec::new();
 5922        let mut unfold_ranges = Vec::new();
 5923        let mut refold_ranges = Vec::new();
 5924
 5925        let selections = self.selections.all::<Point>(cx);
 5926        let mut selections = selections.iter().peekable();
 5927        let mut contiguous_row_selections = Vec::new();
 5928        let mut new_selections = Vec::new();
 5929
 5930        while let Some(selection) = selections.next() {
 5931            // Find all the selections that span a contiguous row range
 5932            let (start_row, end_row) = consume_contiguous_rows(
 5933                &mut contiguous_row_selections,
 5934                selection,
 5935                &display_map,
 5936                &mut selections,
 5937            );
 5938
 5939            // Move the text spanned by the row range to be after the last line of the row range
 5940            if end_row.0 <= buffer.max_point().row {
 5941                let range_to_move =
 5942                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 5943                let insertion_point = display_map
 5944                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 5945                    .0;
 5946
 5947                // Don't move lines across excerpt boundaries
 5948                if buffer
 5949                    .excerpt_boundaries_in_range((
 5950                        Bound::Excluded(range_to_move.start),
 5951                        Bound::Included(insertion_point),
 5952                    ))
 5953                    .next()
 5954                    .is_none()
 5955                {
 5956                    let mut text = String::from("\n");
 5957                    text.extend(buffer.text_for_range(range_to_move.clone()));
 5958                    text.pop(); // Drop trailing newline
 5959                    edits.push((
 5960                        buffer.anchor_after(range_to_move.start)
 5961                            ..buffer.anchor_before(range_to_move.end),
 5962                        String::new(),
 5963                    ));
 5964                    let insertion_anchor = buffer.anchor_after(insertion_point);
 5965                    edits.push((insertion_anchor..insertion_anchor, text));
 5966
 5967                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 5968
 5969                    // Move selections down
 5970                    new_selections.extend(contiguous_row_selections.drain(..).map(
 5971                        |mut selection| {
 5972                            selection.start.row += row_delta;
 5973                            selection.end.row += row_delta;
 5974                            selection
 5975                        },
 5976                    ));
 5977
 5978                    // Move folds down
 5979                    unfold_ranges.push(range_to_move.clone());
 5980                    for fold in display_map.folds_in_range(
 5981                        buffer.anchor_before(range_to_move.start)
 5982                            ..buffer.anchor_after(range_to_move.end),
 5983                    ) {
 5984                        let mut start = fold.range.start.to_point(&buffer);
 5985                        let mut end = fold.range.end.to_point(&buffer);
 5986                        start.row += row_delta;
 5987                        end.row += row_delta;
 5988                        refold_ranges.push((start..end, fold.placeholder.clone()));
 5989                    }
 5990                }
 5991            }
 5992
 5993            // If we didn't move line(s), preserve the existing selections
 5994            new_selections.append(&mut contiguous_row_selections);
 5995        }
 5996
 5997        self.transact(cx, |this, cx| {
 5998            this.unfold_ranges(unfold_ranges, true, true, cx);
 5999            this.buffer.update(cx, |buffer, cx| {
 6000                for (range, text) in edits {
 6001                    buffer.edit([(range, text)], None, cx);
 6002                }
 6003            });
 6004            this.fold_ranges(refold_ranges, true, cx);
 6005            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 6006        });
 6007    }
 6008
 6009    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
 6010        let text_layout_details = &self.text_layout_details(cx);
 6011        self.transact(cx, |this, cx| {
 6012            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6013                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 6014                let line_mode = s.line_mode;
 6015                s.move_with(|display_map, selection| {
 6016                    if !selection.is_empty() || line_mode {
 6017                        return;
 6018                    }
 6019
 6020                    let mut head = selection.head();
 6021                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 6022                    if head.column() == display_map.line_len(head.row()) {
 6023                        transpose_offset = display_map
 6024                            .buffer_snapshot
 6025                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6026                    }
 6027
 6028                    if transpose_offset == 0 {
 6029                        return;
 6030                    }
 6031
 6032                    *head.column_mut() += 1;
 6033                    head = display_map.clip_point(head, Bias::Right);
 6034                    let goal = SelectionGoal::HorizontalPosition(
 6035                        display_map
 6036                            .x_for_display_point(head, &text_layout_details)
 6037                            .into(),
 6038                    );
 6039                    selection.collapse_to(head, goal);
 6040
 6041                    let transpose_start = display_map
 6042                        .buffer_snapshot
 6043                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6044                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 6045                        let transpose_end = display_map
 6046                            .buffer_snapshot
 6047                            .clip_offset(transpose_offset + 1, Bias::Right);
 6048                        if let Some(ch) =
 6049                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 6050                        {
 6051                            edits.push((transpose_start..transpose_offset, String::new()));
 6052                            edits.push((transpose_end..transpose_end, ch.to_string()));
 6053                        }
 6054                    }
 6055                });
 6056                edits
 6057            });
 6058            this.buffer
 6059                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 6060            let selections = this.selections.all::<usize>(cx);
 6061            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6062                s.select(selections);
 6063            });
 6064        });
 6065    }
 6066
 6067    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
 6068        let mut text = String::new();
 6069        let buffer = self.buffer.read(cx).snapshot(cx);
 6070        let mut selections = self.selections.all::<Point>(cx);
 6071        let mut clipboard_selections = Vec::with_capacity(selections.len());
 6072        {
 6073            let max_point = buffer.max_point();
 6074            let mut is_first = true;
 6075            for selection in &mut selections {
 6076                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 6077                if is_entire_line {
 6078                    selection.start = Point::new(selection.start.row, 0);
 6079                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 6080                    selection.goal = SelectionGoal::None;
 6081                }
 6082                if is_first {
 6083                    is_first = false;
 6084                } else {
 6085                    text += "\n";
 6086                }
 6087                let mut len = 0;
 6088                for chunk in buffer.text_for_range(selection.start..selection.end) {
 6089                    text.push_str(chunk);
 6090                    len += chunk.len();
 6091                }
 6092                clipboard_selections.push(ClipboardSelection {
 6093                    len,
 6094                    is_entire_line,
 6095                    first_line_indent: buffer
 6096                        .indent_size_for_line(MultiBufferRow(selection.start.row))
 6097                        .len,
 6098                });
 6099            }
 6100        }
 6101
 6102        self.transact(cx, |this, cx| {
 6103            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6104                s.select(selections);
 6105            });
 6106            this.insert("", cx);
 6107            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 6108        });
 6109    }
 6110
 6111    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
 6112        let selections = self.selections.all::<Point>(cx);
 6113        let buffer = self.buffer.read(cx).read(cx);
 6114        let mut text = String::new();
 6115
 6116        let mut clipboard_selections = Vec::with_capacity(selections.len());
 6117        {
 6118            let max_point = buffer.max_point();
 6119            let mut is_first = true;
 6120            for selection in selections.iter() {
 6121                let mut start = selection.start;
 6122                let mut end = selection.end;
 6123                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 6124                if is_entire_line {
 6125                    start = Point::new(start.row, 0);
 6126                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 6127                }
 6128                if is_first {
 6129                    is_first = false;
 6130                } else {
 6131                    text += "\n";
 6132                }
 6133                let mut len = 0;
 6134                for chunk in buffer.text_for_range(start..end) {
 6135                    text.push_str(chunk);
 6136                    len += chunk.len();
 6137                }
 6138                clipboard_selections.push(ClipboardSelection {
 6139                    len,
 6140                    is_entire_line,
 6141                    first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
 6142                });
 6143            }
 6144        }
 6145
 6146        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 6147    }
 6148
 6149    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
 6150        if self.read_only(cx) {
 6151            return;
 6152        }
 6153
 6154        self.transact(cx, |this, cx| {
 6155            if let Some(item) = cx.read_from_clipboard() {
 6156                let clipboard_text = Cow::Borrowed(item.text());
 6157                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
 6158                    let old_selections = this.selections.all::<usize>(cx);
 6159                    let all_selections_were_entire_line =
 6160                        clipboard_selections.iter().all(|s| s.is_entire_line);
 6161                    let first_selection_indent_column =
 6162                        clipboard_selections.first().map(|s| s.first_line_indent);
 6163                    if clipboard_selections.len() != old_selections.len() {
 6164                        clipboard_selections.drain(..);
 6165                    }
 6166
 6167                    this.buffer.update(cx, |buffer, cx| {
 6168                        let snapshot = buffer.read(cx);
 6169                        let mut start_offset = 0;
 6170                        let mut edits = Vec::new();
 6171                        let mut original_indent_columns = Vec::new();
 6172                        let line_mode = this.selections.line_mode;
 6173                        for (ix, selection) in old_selections.iter().enumerate() {
 6174                            let to_insert;
 6175                            let entire_line;
 6176                            let original_indent_column;
 6177                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 6178                                let end_offset = start_offset + clipboard_selection.len;
 6179                                to_insert = &clipboard_text[start_offset..end_offset];
 6180                                entire_line = clipboard_selection.is_entire_line;
 6181                                start_offset = end_offset + 1;
 6182                                original_indent_column =
 6183                                    Some(clipboard_selection.first_line_indent);
 6184                            } else {
 6185                                to_insert = clipboard_text.as_str();
 6186                                entire_line = all_selections_were_entire_line;
 6187                                original_indent_column = first_selection_indent_column
 6188                            }
 6189
 6190                            // If the corresponding selection was empty when this slice of the
 6191                            // clipboard text was written, then the entire line containing the
 6192                            // selection was copied. If this selection is also currently empty,
 6193                            // then paste the line before the current line of the buffer.
 6194                            let range = if selection.is_empty() && !line_mode && entire_line {
 6195                                let column = selection.start.to_point(&snapshot).column as usize;
 6196                                let line_start = selection.start - column;
 6197                                line_start..line_start
 6198                            } else {
 6199                                selection.range()
 6200                            };
 6201
 6202                            edits.push((range, to_insert));
 6203                            original_indent_columns.extend(original_indent_column);
 6204                        }
 6205                        drop(snapshot);
 6206
 6207                        buffer.edit(
 6208                            edits,
 6209                            Some(AutoindentMode::Block {
 6210                                original_indent_columns,
 6211                            }),
 6212                            cx,
 6213                        );
 6214                    });
 6215
 6216                    let selections = this.selections.all::<usize>(cx);
 6217                    this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6218                } else {
 6219                    this.insert(&clipboard_text, cx);
 6220                }
 6221            }
 6222        });
 6223    }
 6224
 6225    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
 6226        if self.read_only(cx) {
 6227            return;
 6228        }
 6229
 6230        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 6231            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
 6232                self.change_selections(None, cx, |s| {
 6233                    s.select_anchors(selections.to_vec());
 6234                });
 6235            }
 6236            self.request_autoscroll(Autoscroll::fit(), cx);
 6237            self.unmark_text(cx);
 6238            self.refresh_inline_completion(true, cx);
 6239            cx.emit(EditorEvent::Edited);
 6240            cx.emit(EditorEvent::TransactionUndone {
 6241                transaction_id: tx_id,
 6242            });
 6243        }
 6244    }
 6245
 6246    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 6247        if self.read_only(cx) {
 6248            return;
 6249        }
 6250
 6251        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 6252            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
 6253            {
 6254                self.change_selections(None, cx, |s| {
 6255                    s.select_anchors(selections.to_vec());
 6256                });
 6257            }
 6258            self.request_autoscroll(Autoscroll::fit(), cx);
 6259            self.unmark_text(cx);
 6260            self.refresh_inline_completion(true, cx);
 6261            cx.emit(EditorEvent::Edited);
 6262        }
 6263    }
 6264
 6265    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 6266        self.buffer
 6267            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 6268    }
 6269
 6270    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut ViewContext<Self>) {
 6271        self.buffer
 6272            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
 6273    }
 6274
 6275    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 6276        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6277            let line_mode = s.line_mode;
 6278            s.move_with(|map, selection| {
 6279                let cursor = if selection.is_empty() && !line_mode {
 6280                    movement::left(map, selection.start)
 6281                } else {
 6282                    selection.start
 6283                };
 6284                selection.collapse_to(cursor, SelectionGoal::None);
 6285            });
 6286        })
 6287    }
 6288
 6289    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 6290        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6291            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 6292        })
 6293    }
 6294
 6295    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 6296        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6297            let line_mode = s.line_mode;
 6298            s.move_with(|map, selection| {
 6299                let cursor = if selection.is_empty() && !line_mode {
 6300                    movement::right(map, selection.end)
 6301                } else {
 6302                    selection.end
 6303                };
 6304                selection.collapse_to(cursor, SelectionGoal::None)
 6305            });
 6306        })
 6307    }
 6308
 6309    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 6310        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6311            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 6312        })
 6313    }
 6314
 6315    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 6316        if self.take_rename(true, cx).is_some() {
 6317            return;
 6318        }
 6319
 6320        if matches!(self.mode, EditorMode::SingleLine) {
 6321            cx.propagate();
 6322            return;
 6323        }
 6324
 6325        let text_layout_details = &self.text_layout_details(cx);
 6326
 6327        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6328            let line_mode = s.line_mode;
 6329            s.move_with(|map, selection| {
 6330                if !selection.is_empty() && !line_mode {
 6331                    selection.goal = SelectionGoal::None;
 6332                }
 6333                let (cursor, goal) = movement::up(
 6334                    map,
 6335                    selection.start,
 6336                    selection.goal,
 6337                    false,
 6338                    &text_layout_details,
 6339                );
 6340                selection.collapse_to(cursor, goal);
 6341            });
 6342        })
 6343    }
 6344
 6345    pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
 6346        if self.take_rename(true, cx).is_some() {
 6347            return;
 6348        }
 6349
 6350        if matches!(self.mode, EditorMode::SingleLine) {
 6351            cx.propagate();
 6352            return;
 6353        }
 6354
 6355        let text_layout_details = &self.text_layout_details(cx);
 6356
 6357        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6358            let line_mode = s.line_mode;
 6359            s.move_with(|map, selection| {
 6360                if !selection.is_empty() && !line_mode {
 6361                    selection.goal = SelectionGoal::None;
 6362                }
 6363                let (cursor, goal) = movement::up_by_rows(
 6364                    map,
 6365                    selection.start,
 6366                    action.lines,
 6367                    selection.goal,
 6368                    false,
 6369                    &text_layout_details,
 6370                );
 6371                selection.collapse_to(cursor, goal);
 6372            });
 6373        })
 6374    }
 6375
 6376    pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext<Self>) {
 6377        if self.take_rename(true, cx).is_some() {
 6378            return;
 6379        }
 6380
 6381        if matches!(self.mode, EditorMode::SingleLine) {
 6382            cx.propagate();
 6383            return;
 6384        }
 6385
 6386        let text_layout_details = &self.text_layout_details(cx);
 6387
 6388        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6389            let line_mode = s.line_mode;
 6390            s.move_with(|map, selection| {
 6391                if !selection.is_empty() && !line_mode {
 6392                    selection.goal = SelectionGoal::None;
 6393                }
 6394                let (cursor, goal) = movement::down_by_rows(
 6395                    map,
 6396                    selection.start,
 6397                    action.lines,
 6398                    selection.goal,
 6399                    false,
 6400                    &text_layout_details,
 6401                );
 6402                selection.collapse_to(cursor, goal);
 6403            });
 6404        })
 6405    }
 6406
 6407    pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext<Self>) {
 6408        let text_layout_details = &self.text_layout_details(cx);
 6409        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6410            s.move_heads_with(|map, head, goal| {
 6411                movement::down_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 6412            })
 6413        })
 6414    }
 6415
 6416    pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext<Self>) {
 6417        let text_layout_details = &self.text_layout_details(cx);
 6418        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6419            s.move_heads_with(|map, head, goal| {
 6420                movement::up_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 6421            })
 6422        })
 6423    }
 6424
 6425    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
 6426        if self.take_rename(true, cx).is_some() {
 6427            return;
 6428        }
 6429
 6430        if matches!(self.mode, EditorMode::SingleLine) {
 6431            cx.propagate();
 6432            return;
 6433        }
 6434
 6435        let row_count = if let Some(row_count) = self.visible_line_count() {
 6436            row_count as u32 - 1
 6437        } else {
 6438            return;
 6439        };
 6440
 6441        let autoscroll = if action.center_cursor {
 6442            Autoscroll::center()
 6443        } else {
 6444            Autoscroll::fit()
 6445        };
 6446
 6447        let text_layout_details = &self.text_layout_details(cx);
 6448
 6449        self.change_selections(Some(autoscroll), cx, |s| {
 6450            let line_mode = s.line_mode;
 6451            s.move_with(|map, selection| {
 6452                if !selection.is_empty() && !line_mode {
 6453                    selection.goal = SelectionGoal::None;
 6454                }
 6455                let (cursor, goal) = movement::up_by_rows(
 6456                    map,
 6457                    selection.end,
 6458                    row_count,
 6459                    selection.goal,
 6460                    false,
 6461                    &text_layout_details,
 6462                );
 6463                selection.collapse_to(cursor, goal);
 6464            });
 6465        });
 6466    }
 6467
 6468    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 6469        let text_layout_details = &self.text_layout_details(cx);
 6470        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6471            s.move_heads_with(|map, head, goal| {
 6472                movement::up(map, head, goal, false, &text_layout_details)
 6473            })
 6474        })
 6475    }
 6476
 6477    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 6478        self.take_rename(true, cx);
 6479
 6480        if self.mode == EditorMode::SingleLine {
 6481            cx.propagate();
 6482            return;
 6483        }
 6484
 6485        let text_layout_details = &self.text_layout_details(cx);
 6486        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6487            let line_mode = s.line_mode;
 6488            s.move_with(|map, selection| {
 6489                if !selection.is_empty() && !line_mode {
 6490                    selection.goal = SelectionGoal::None;
 6491                }
 6492                let (cursor, goal) = movement::down(
 6493                    map,
 6494                    selection.end,
 6495                    selection.goal,
 6496                    false,
 6497                    &text_layout_details,
 6498                );
 6499                selection.collapse_to(cursor, goal);
 6500            });
 6501        });
 6502    }
 6503
 6504    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
 6505        if self.take_rename(true, cx).is_some() {
 6506            return;
 6507        }
 6508
 6509        if self
 6510            .context_menu
 6511            .write()
 6512            .as_mut()
 6513            .map(|menu| menu.select_last(self.project.as_ref(), cx))
 6514            .unwrap_or(false)
 6515        {
 6516            return;
 6517        }
 6518
 6519        if matches!(self.mode, EditorMode::SingleLine) {
 6520            cx.propagate();
 6521            return;
 6522        }
 6523
 6524        let row_count = if let Some(row_count) = self.visible_line_count() {
 6525            row_count as u32 - 1
 6526        } else {
 6527            return;
 6528        };
 6529
 6530        let autoscroll = if action.center_cursor {
 6531            Autoscroll::center()
 6532        } else {
 6533            Autoscroll::fit()
 6534        };
 6535
 6536        let text_layout_details = &self.text_layout_details(cx);
 6537        self.change_selections(Some(autoscroll), cx, |s| {
 6538            let line_mode = s.line_mode;
 6539            s.move_with(|map, selection| {
 6540                if !selection.is_empty() && !line_mode {
 6541                    selection.goal = SelectionGoal::None;
 6542                }
 6543                let (cursor, goal) = movement::down_by_rows(
 6544                    map,
 6545                    selection.end,
 6546                    row_count,
 6547                    selection.goal,
 6548                    false,
 6549                    &text_layout_details,
 6550                );
 6551                selection.collapse_to(cursor, goal);
 6552            });
 6553        });
 6554    }
 6555
 6556    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 6557        let text_layout_details = &self.text_layout_details(cx);
 6558        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6559            s.move_heads_with(|map, head, goal| {
 6560                movement::down(map, head, goal, false, &text_layout_details)
 6561            })
 6562        });
 6563    }
 6564
 6565    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
 6566        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6567            context_menu.select_first(self.project.as_ref(), cx);
 6568        }
 6569    }
 6570
 6571    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
 6572        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6573            context_menu.select_prev(self.project.as_ref(), cx);
 6574        }
 6575    }
 6576
 6577    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
 6578        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6579            context_menu.select_next(self.project.as_ref(), cx);
 6580        }
 6581    }
 6582
 6583    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
 6584        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6585            context_menu.select_last(self.project.as_ref(), cx);
 6586        }
 6587    }
 6588
 6589    pub fn move_to_previous_word_start(
 6590        &mut self,
 6591        _: &MoveToPreviousWordStart,
 6592        cx: &mut ViewContext<Self>,
 6593    ) {
 6594        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6595            s.move_cursors_with(|map, head, _| {
 6596                (
 6597                    movement::previous_word_start(map, head),
 6598                    SelectionGoal::None,
 6599                )
 6600            });
 6601        })
 6602    }
 6603
 6604    pub fn move_to_previous_subword_start(
 6605        &mut self,
 6606        _: &MoveToPreviousSubwordStart,
 6607        cx: &mut ViewContext<Self>,
 6608    ) {
 6609        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6610            s.move_cursors_with(|map, head, _| {
 6611                (
 6612                    movement::previous_subword_start(map, head),
 6613                    SelectionGoal::None,
 6614                )
 6615            });
 6616        })
 6617    }
 6618
 6619    pub fn select_to_previous_word_start(
 6620        &mut self,
 6621        _: &SelectToPreviousWordStart,
 6622        cx: &mut ViewContext<Self>,
 6623    ) {
 6624        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6625            s.move_heads_with(|map, head, _| {
 6626                (
 6627                    movement::previous_word_start(map, head),
 6628                    SelectionGoal::None,
 6629                )
 6630            });
 6631        })
 6632    }
 6633
 6634    pub fn select_to_previous_subword_start(
 6635        &mut self,
 6636        _: &SelectToPreviousSubwordStart,
 6637        cx: &mut ViewContext<Self>,
 6638    ) {
 6639        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6640            s.move_heads_with(|map, head, _| {
 6641                (
 6642                    movement::previous_subword_start(map, head),
 6643                    SelectionGoal::None,
 6644                )
 6645            });
 6646        })
 6647    }
 6648
 6649    pub fn delete_to_previous_word_start(
 6650        &mut self,
 6651        _: &DeleteToPreviousWordStart,
 6652        cx: &mut ViewContext<Self>,
 6653    ) {
 6654        self.transact(cx, |this, cx| {
 6655            this.select_autoclose_pair(cx);
 6656            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6657                let line_mode = s.line_mode;
 6658                s.move_with(|map, selection| {
 6659                    if selection.is_empty() && !line_mode {
 6660                        let cursor = movement::previous_word_start(map, selection.head());
 6661                        selection.set_head(cursor, SelectionGoal::None);
 6662                    }
 6663                });
 6664            });
 6665            this.insert("", cx);
 6666        });
 6667    }
 6668
 6669    pub fn delete_to_previous_subword_start(
 6670        &mut self,
 6671        _: &DeleteToPreviousSubwordStart,
 6672        cx: &mut ViewContext<Self>,
 6673    ) {
 6674        self.transact(cx, |this, cx| {
 6675            this.select_autoclose_pair(cx);
 6676            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6677                let line_mode = s.line_mode;
 6678                s.move_with(|map, selection| {
 6679                    if selection.is_empty() && !line_mode {
 6680                        let cursor = movement::previous_subword_start(map, selection.head());
 6681                        selection.set_head(cursor, SelectionGoal::None);
 6682                    }
 6683                });
 6684            });
 6685            this.insert("", cx);
 6686        });
 6687    }
 6688
 6689    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 6690        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6691            s.move_cursors_with(|map, head, _| {
 6692                (movement::next_word_end(map, head), SelectionGoal::None)
 6693            });
 6694        })
 6695    }
 6696
 6697    pub fn move_to_next_subword_end(
 6698        &mut self,
 6699        _: &MoveToNextSubwordEnd,
 6700        cx: &mut ViewContext<Self>,
 6701    ) {
 6702        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6703            s.move_cursors_with(|map, head, _| {
 6704                (movement::next_subword_end(map, head), SelectionGoal::None)
 6705            });
 6706        })
 6707    }
 6708
 6709    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 6710        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6711            s.move_heads_with(|map, head, _| {
 6712                (movement::next_word_end(map, head), SelectionGoal::None)
 6713            });
 6714        })
 6715    }
 6716
 6717    pub fn select_to_next_subword_end(
 6718        &mut self,
 6719        _: &SelectToNextSubwordEnd,
 6720        cx: &mut ViewContext<Self>,
 6721    ) {
 6722        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6723            s.move_heads_with(|map, head, _| {
 6724                (movement::next_subword_end(map, head), SelectionGoal::None)
 6725            });
 6726        })
 6727    }
 6728
 6729    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
 6730        self.transact(cx, |this, cx| {
 6731            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6732                let line_mode = s.line_mode;
 6733                s.move_with(|map, selection| {
 6734                    if selection.is_empty() && !line_mode {
 6735                        let cursor = movement::next_word_end(map, selection.head());
 6736                        selection.set_head(cursor, SelectionGoal::None);
 6737                    }
 6738                });
 6739            });
 6740            this.insert("", cx);
 6741        });
 6742    }
 6743
 6744    pub fn delete_to_next_subword_end(
 6745        &mut self,
 6746        _: &DeleteToNextSubwordEnd,
 6747        cx: &mut ViewContext<Self>,
 6748    ) {
 6749        self.transact(cx, |this, cx| {
 6750            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6751                s.move_with(|map, selection| {
 6752                    if selection.is_empty() {
 6753                        let cursor = movement::next_subword_end(map, selection.head());
 6754                        selection.set_head(cursor, SelectionGoal::None);
 6755                    }
 6756                });
 6757            });
 6758            this.insert("", cx);
 6759        });
 6760    }
 6761
 6762    pub fn move_to_beginning_of_line(
 6763        &mut self,
 6764        action: &MoveToBeginningOfLine,
 6765        cx: &mut ViewContext<Self>,
 6766    ) {
 6767        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6768            s.move_cursors_with(|map, head, _| {
 6769                (
 6770                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 6771                    SelectionGoal::None,
 6772                )
 6773            });
 6774        })
 6775    }
 6776
 6777    pub fn select_to_beginning_of_line(
 6778        &mut self,
 6779        action: &SelectToBeginningOfLine,
 6780        cx: &mut ViewContext<Self>,
 6781    ) {
 6782        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6783            s.move_heads_with(|map, head, _| {
 6784                (
 6785                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 6786                    SelectionGoal::None,
 6787                )
 6788            });
 6789        });
 6790    }
 6791
 6792    pub fn delete_to_beginning_of_line(
 6793        &mut self,
 6794        _: &DeleteToBeginningOfLine,
 6795        cx: &mut ViewContext<Self>,
 6796    ) {
 6797        self.transact(cx, |this, cx| {
 6798            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6799                s.move_with(|_, selection| {
 6800                    selection.reversed = true;
 6801                });
 6802            });
 6803
 6804            this.select_to_beginning_of_line(
 6805                &SelectToBeginningOfLine {
 6806                    stop_at_soft_wraps: false,
 6807                },
 6808                cx,
 6809            );
 6810            this.backspace(&Backspace, cx);
 6811        });
 6812    }
 6813
 6814    pub fn move_to_end_of_line(&mut self, action: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 6815        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6816            s.move_cursors_with(|map, head, _| {
 6817                (
 6818                    movement::line_end(map, head, action.stop_at_soft_wraps),
 6819                    SelectionGoal::None,
 6820                )
 6821            });
 6822        })
 6823    }
 6824
 6825    pub fn select_to_end_of_line(
 6826        &mut self,
 6827        action: &SelectToEndOfLine,
 6828        cx: &mut ViewContext<Self>,
 6829    ) {
 6830        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6831            s.move_heads_with(|map, head, _| {
 6832                (
 6833                    movement::line_end(map, head, action.stop_at_soft_wraps),
 6834                    SelectionGoal::None,
 6835                )
 6836            });
 6837        })
 6838    }
 6839
 6840    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 6841        self.transact(cx, |this, cx| {
 6842            this.select_to_end_of_line(
 6843                &SelectToEndOfLine {
 6844                    stop_at_soft_wraps: false,
 6845                },
 6846                cx,
 6847            );
 6848            this.delete(&Delete, cx);
 6849        });
 6850    }
 6851
 6852    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 6853        self.transact(cx, |this, cx| {
 6854            this.select_to_end_of_line(
 6855                &SelectToEndOfLine {
 6856                    stop_at_soft_wraps: false,
 6857                },
 6858                cx,
 6859            );
 6860            this.cut(&Cut, cx);
 6861        });
 6862    }
 6863
 6864    pub fn move_to_start_of_paragraph(
 6865        &mut self,
 6866        _: &MoveToStartOfParagraph,
 6867        cx: &mut ViewContext<Self>,
 6868    ) {
 6869        if matches!(self.mode, EditorMode::SingleLine) {
 6870            cx.propagate();
 6871            return;
 6872        }
 6873
 6874        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6875            s.move_with(|map, selection| {
 6876                selection.collapse_to(
 6877                    movement::start_of_paragraph(map, selection.head(), 1),
 6878                    SelectionGoal::None,
 6879                )
 6880            });
 6881        })
 6882    }
 6883
 6884    pub fn move_to_end_of_paragraph(
 6885        &mut self,
 6886        _: &MoveToEndOfParagraph,
 6887        cx: &mut ViewContext<Self>,
 6888    ) {
 6889        if matches!(self.mode, EditorMode::SingleLine) {
 6890            cx.propagate();
 6891            return;
 6892        }
 6893
 6894        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6895            s.move_with(|map, selection| {
 6896                selection.collapse_to(
 6897                    movement::end_of_paragraph(map, selection.head(), 1),
 6898                    SelectionGoal::None,
 6899                )
 6900            });
 6901        })
 6902    }
 6903
 6904    pub fn select_to_start_of_paragraph(
 6905        &mut self,
 6906        _: &SelectToStartOfParagraph,
 6907        cx: &mut ViewContext<Self>,
 6908    ) {
 6909        if matches!(self.mode, EditorMode::SingleLine) {
 6910            cx.propagate();
 6911            return;
 6912        }
 6913
 6914        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6915            s.move_heads_with(|map, head, _| {
 6916                (
 6917                    movement::start_of_paragraph(map, head, 1),
 6918                    SelectionGoal::None,
 6919                )
 6920            });
 6921        })
 6922    }
 6923
 6924    pub fn select_to_end_of_paragraph(
 6925        &mut self,
 6926        _: &SelectToEndOfParagraph,
 6927        cx: &mut ViewContext<Self>,
 6928    ) {
 6929        if matches!(self.mode, EditorMode::SingleLine) {
 6930            cx.propagate();
 6931            return;
 6932        }
 6933
 6934        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6935            s.move_heads_with(|map, head, _| {
 6936                (
 6937                    movement::end_of_paragraph(map, head, 1),
 6938                    SelectionGoal::None,
 6939                )
 6940            });
 6941        })
 6942    }
 6943
 6944    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 6945        if matches!(self.mode, EditorMode::SingleLine) {
 6946            cx.propagate();
 6947            return;
 6948        }
 6949
 6950        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6951            s.select_ranges(vec![0..0]);
 6952        });
 6953    }
 6954
 6955    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 6956        let mut selection = self.selections.last::<Point>(cx);
 6957        selection.set_head(Point::zero(), SelectionGoal::None);
 6958
 6959        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6960            s.select(vec![selection]);
 6961        });
 6962    }
 6963
 6964    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 6965        if matches!(self.mode, EditorMode::SingleLine) {
 6966            cx.propagate();
 6967            return;
 6968        }
 6969
 6970        let cursor = self.buffer.read(cx).read(cx).len();
 6971        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6972            s.select_ranges(vec![cursor..cursor])
 6973        });
 6974    }
 6975
 6976    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 6977        self.nav_history = nav_history;
 6978    }
 6979
 6980    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 6981        self.nav_history.as_ref()
 6982    }
 6983
 6984    fn push_to_nav_history(
 6985        &mut self,
 6986        cursor_anchor: Anchor,
 6987        new_position: Option<Point>,
 6988        cx: &mut ViewContext<Self>,
 6989    ) {
 6990        if let Some(nav_history) = self.nav_history.as_mut() {
 6991            let buffer = self.buffer.read(cx).read(cx);
 6992            let cursor_position = cursor_anchor.to_point(&buffer);
 6993            let scroll_state = self.scroll_manager.anchor();
 6994            let scroll_top_row = scroll_state.top_row(&buffer);
 6995            drop(buffer);
 6996
 6997            if let Some(new_position) = new_position {
 6998                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 6999                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 7000                    return;
 7001                }
 7002            }
 7003
 7004            nav_history.push(
 7005                Some(NavigationData {
 7006                    cursor_anchor,
 7007                    cursor_position,
 7008                    scroll_anchor: scroll_state,
 7009                    scroll_top_row,
 7010                }),
 7011                cx,
 7012            );
 7013        }
 7014    }
 7015
 7016    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 7017        let buffer = self.buffer.read(cx).snapshot(cx);
 7018        let mut selection = self.selections.first::<usize>(cx);
 7019        selection.set_head(buffer.len(), SelectionGoal::None);
 7020        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7021            s.select(vec![selection]);
 7022        });
 7023    }
 7024
 7025    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 7026        let end = self.buffer.read(cx).read(cx).len();
 7027        self.change_selections(None, cx, |s| {
 7028            s.select_ranges(vec![0..end]);
 7029        });
 7030    }
 7031
 7032    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 7033        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7034        let mut selections = self.selections.all::<Point>(cx);
 7035        let max_point = display_map.buffer_snapshot.max_point();
 7036        for selection in &mut selections {
 7037            let rows = selection.spanned_rows(true, &display_map);
 7038            selection.start = Point::new(rows.start.0, 0);
 7039            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
 7040            selection.reversed = false;
 7041        }
 7042        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7043            s.select(selections);
 7044        });
 7045    }
 7046
 7047    pub fn split_selection_into_lines(
 7048        &mut self,
 7049        _: &SplitSelectionIntoLines,
 7050        cx: &mut ViewContext<Self>,
 7051    ) {
 7052        let mut to_unfold = Vec::new();
 7053        let mut new_selection_ranges = Vec::new();
 7054        {
 7055            let selections = self.selections.all::<Point>(cx);
 7056            let buffer = self.buffer.read(cx).read(cx);
 7057            for selection in selections {
 7058                for row in selection.start.row..selection.end.row {
 7059                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
 7060                    new_selection_ranges.push(cursor..cursor);
 7061                }
 7062                new_selection_ranges.push(selection.end..selection.end);
 7063                to_unfold.push(selection.start..selection.end);
 7064            }
 7065        }
 7066        self.unfold_ranges(to_unfold, true, true, cx);
 7067        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7068            s.select_ranges(new_selection_ranges);
 7069        });
 7070    }
 7071
 7072    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 7073        self.add_selection(true, cx);
 7074    }
 7075
 7076    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 7077        self.add_selection(false, cx);
 7078    }
 7079
 7080    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 7081        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7082        let mut selections = self.selections.all::<Point>(cx);
 7083        let text_layout_details = self.text_layout_details(cx);
 7084        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 7085            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 7086            let range = oldest_selection.display_range(&display_map).sorted();
 7087
 7088            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 7089            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 7090            let positions = start_x.min(end_x)..start_x.max(end_x);
 7091
 7092            selections.clear();
 7093            let mut stack = Vec::new();
 7094            for row in range.start.row().0..=range.end.row().0 {
 7095                if let Some(selection) = self.selections.build_columnar_selection(
 7096                    &display_map,
 7097                    DisplayRow(row),
 7098                    &positions,
 7099                    oldest_selection.reversed,
 7100                    &text_layout_details,
 7101                ) {
 7102                    stack.push(selection.id);
 7103                    selections.push(selection);
 7104                }
 7105            }
 7106
 7107            if above {
 7108                stack.reverse();
 7109            }
 7110
 7111            AddSelectionsState { above, stack }
 7112        });
 7113
 7114        let last_added_selection = *state.stack.last().unwrap();
 7115        let mut new_selections = Vec::new();
 7116        if above == state.above {
 7117            let end_row = if above {
 7118                DisplayRow(0)
 7119            } else {
 7120                display_map.max_point().row()
 7121            };
 7122
 7123            'outer: for selection in selections {
 7124                if selection.id == last_added_selection {
 7125                    let range = selection.display_range(&display_map).sorted();
 7126                    debug_assert_eq!(range.start.row(), range.end.row());
 7127                    let mut row = range.start.row();
 7128                    let positions =
 7129                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 7130                            px(start)..px(end)
 7131                        } else {
 7132                            let start_x =
 7133                                display_map.x_for_display_point(range.start, &text_layout_details);
 7134                            let end_x =
 7135                                display_map.x_for_display_point(range.end, &text_layout_details);
 7136                            start_x.min(end_x)..start_x.max(end_x)
 7137                        };
 7138
 7139                    while row != end_row {
 7140                        if above {
 7141                            row.0 -= 1;
 7142                        } else {
 7143                            row.0 += 1;
 7144                        }
 7145
 7146                        if let Some(new_selection) = self.selections.build_columnar_selection(
 7147                            &display_map,
 7148                            row,
 7149                            &positions,
 7150                            selection.reversed,
 7151                            &text_layout_details,
 7152                        ) {
 7153                            state.stack.push(new_selection.id);
 7154                            if above {
 7155                                new_selections.push(new_selection);
 7156                                new_selections.push(selection);
 7157                            } else {
 7158                                new_selections.push(selection);
 7159                                new_selections.push(new_selection);
 7160                            }
 7161
 7162                            continue 'outer;
 7163                        }
 7164                    }
 7165                }
 7166
 7167                new_selections.push(selection);
 7168            }
 7169        } else {
 7170            new_selections = selections;
 7171            new_selections.retain(|s| s.id != last_added_selection);
 7172            state.stack.pop();
 7173        }
 7174
 7175        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7176            s.select(new_selections);
 7177        });
 7178        if state.stack.len() > 1 {
 7179            self.add_selections_state = Some(state);
 7180        }
 7181    }
 7182
 7183    pub fn select_next_match_internal(
 7184        &mut self,
 7185        display_map: &DisplaySnapshot,
 7186        replace_newest: bool,
 7187        autoscroll: Option<Autoscroll>,
 7188        cx: &mut ViewContext<Self>,
 7189    ) -> Result<()> {
 7190        fn select_next_match_ranges(
 7191            this: &mut Editor,
 7192            range: Range<usize>,
 7193            replace_newest: bool,
 7194            auto_scroll: Option<Autoscroll>,
 7195            cx: &mut ViewContext<Editor>,
 7196        ) {
 7197            this.unfold_ranges([range.clone()], false, true, cx);
 7198            this.change_selections(auto_scroll, cx, |s| {
 7199                if replace_newest {
 7200                    s.delete(s.newest_anchor().id);
 7201                }
 7202                s.insert_range(range.clone());
 7203            });
 7204        }
 7205
 7206        let buffer = &display_map.buffer_snapshot;
 7207        let mut selections = self.selections.all::<usize>(cx);
 7208        if let Some(mut select_next_state) = self.select_next_state.take() {
 7209            let query = &select_next_state.query;
 7210            if !select_next_state.done {
 7211                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 7212                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 7213                let mut next_selected_range = None;
 7214
 7215                let bytes_after_last_selection =
 7216                    buffer.bytes_in_range(last_selection.end..buffer.len());
 7217                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 7218                let query_matches = query
 7219                    .stream_find_iter(bytes_after_last_selection)
 7220                    .map(|result| (last_selection.end, result))
 7221                    .chain(
 7222                        query
 7223                            .stream_find_iter(bytes_before_first_selection)
 7224                            .map(|result| (0, result)),
 7225                    );
 7226
 7227                for (start_offset, query_match) in query_matches {
 7228                    let query_match = query_match.unwrap(); // can only fail due to I/O
 7229                    let offset_range =
 7230                        start_offset + query_match.start()..start_offset + query_match.end();
 7231                    let display_range = offset_range.start.to_display_point(&display_map)
 7232                        ..offset_range.end.to_display_point(&display_map);
 7233
 7234                    if !select_next_state.wordwise
 7235                        || (!movement::is_inside_word(&display_map, display_range.start)
 7236                            && !movement::is_inside_word(&display_map, display_range.end))
 7237                    {
 7238                        // TODO: This is n^2, because we might check all the selections
 7239                        if !selections
 7240                            .iter()
 7241                            .any(|selection| selection.range().overlaps(&offset_range))
 7242                        {
 7243                            next_selected_range = Some(offset_range);
 7244                            break;
 7245                        }
 7246                    }
 7247                }
 7248
 7249                if let Some(next_selected_range) = next_selected_range {
 7250                    select_next_match_ranges(
 7251                        self,
 7252                        next_selected_range,
 7253                        replace_newest,
 7254                        autoscroll,
 7255                        cx,
 7256                    );
 7257                } else {
 7258                    select_next_state.done = true;
 7259                }
 7260            }
 7261
 7262            self.select_next_state = Some(select_next_state);
 7263        } else {
 7264            let mut only_carets = true;
 7265            let mut same_text_selected = true;
 7266            let mut selected_text = None;
 7267
 7268            let mut selections_iter = selections.iter().peekable();
 7269            while let Some(selection) = selections_iter.next() {
 7270                if selection.start != selection.end {
 7271                    only_carets = false;
 7272                }
 7273
 7274                if same_text_selected {
 7275                    if selected_text.is_none() {
 7276                        selected_text =
 7277                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 7278                    }
 7279
 7280                    if let Some(next_selection) = selections_iter.peek() {
 7281                        if next_selection.range().len() == selection.range().len() {
 7282                            let next_selected_text = buffer
 7283                                .text_for_range(next_selection.range())
 7284                                .collect::<String>();
 7285                            if Some(next_selected_text) != selected_text {
 7286                                same_text_selected = false;
 7287                                selected_text = None;
 7288                            }
 7289                        } else {
 7290                            same_text_selected = false;
 7291                            selected_text = None;
 7292                        }
 7293                    }
 7294                }
 7295            }
 7296
 7297            if only_carets {
 7298                for selection in &mut selections {
 7299                    let word_range = movement::surrounding_word(
 7300                        &display_map,
 7301                        selection.start.to_display_point(&display_map),
 7302                    );
 7303                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 7304                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 7305                    selection.goal = SelectionGoal::None;
 7306                    selection.reversed = false;
 7307                    select_next_match_ranges(
 7308                        self,
 7309                        selection.start..selection.end,
 7310                        replace_newest,
 7311                        autoscroll,
 7312                        cx,
 7313                    );
 7314                }
 7315
 7316                if selections.len() == 1 {
 7317                    let selection = selections
 7318                        .last()
 7319                        .expect("ensured that there's only one selection");
 7320                    let query = buffer
 7321                        .text_for_range(selection.start..selection.end)
 7322                        .collect::<String>();
 7323                    let is_empty = query.is_empty();
 7324                    let select_state = SelectNextState {
 7325                        query: AhoCorasick::new(&[query])?,
 7326                        wordwise: true,
 7327                        done: is_empty,
 7328                    };
 7329                    self.select_next_state = Some(select_state);
 7330                } else {
 7331                    self.select_next_state = None;
 7332                }
 7333            } else if let Some(selected_text) = selected_text {
 7334                self.select_next_state = Some(SelectNextState {
 7335                    query: AhoCorasick::new(&[selected_text])?,
 7336                    wordwise: false,
 7337                    done: false,
 7338                });
 7339                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
 7340            }
 7341        }
 7342        Ok(())
 7343    }
 7344
 7345    pub fn select_all_matches(
 7346        &mut self,
 7347        _action: &SelectAllMatches,
 7348        cx: &mut ViewContext<Self>,
 7349    ) -> Result<()> {
 7350        self.push_to_selection_history();
 7351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7352
 7353        self.select_next_match_internal(&display_map, false, None, cx)?;
 7354        let Some(select_next_state) = self.select_next_state.as_mut() else {
 7355            return Ok(());
 7356        };
 7357        if select_next_state.done {
 7358            return Ok(());
 7359        }
 7360
 7361        let mut new_selections = self.selections.all::<usize>(cx);
 7362
 7363        let buffer = &display_map.buffer_snapshot;
 7364        let query_matches = select_next_state
 7365            .query
 7366            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
 7367
 7368        for query_match in query_matches {
 7369            let query_match = query_match.unwrap(); // can only fail due to I/O
 7370            let offset_range = query_match.start()..query_match.end();
 7371            let display_range = offset_range.start.to_display_point(&display_map)
 7372                ..offset_range.end.to_display_point(&display_map);
 7373
 7374            if !select_next_state.wordwise
 7375                || (!movement::is_inside_word(&display_map, display_range.start)
 7376                    && !movement::is_inside_word(&display_map, display_range.end))
 7377            {
 7378                self.selections.change_with(cx, |selections| {
 7379                    new_selections.push(Selection {
 7380                        id: selections.new_selection_id(),
 7381                        start: offset_range.start,
 7382                        end: offset_range.end,
 7383                        reversed: false,
 7384                        goal: SelectionGoal::None,
 7385                    });
 7386                });
 7387            }
 7388        }
 7389
 7390        new_selections.sort_by_key(|selection| selection.start);
 7391        let mut ix = 0;
 7392        while ix + 1 < new_selections.len() {
 7393            let current_selection = &new_selections[ix];
 7394            let next_selection = &new_selections[ix + 1];
 7395            if current_selection.range().overlaps(&next_selection.range()) {
 7396                if current_selection.id < next_selection.id {
 7397                    new_selections.remove(ix + 1);
 7398                } else {
 7399                    new_selections.remove(ix);
 7400                }
 7401            } else {
 7402                ix += 1;
 7403            }
 7404        }
 7405
 7406        select_next_state.done = true;
 7407        self.unfold_ranges(
 7408            new_selections.iter().map(|selection| selection.range()),
 7409            false,
 7410            false,
 7411            cx,
 7412        );
 7413        self.change_selections(Some(Autoscroll::fit()), cx, |selections| {
 7414            selections.select(new_selections)
 7415        });
 7416
 7417        Ok(())
 7418    }
 7419
 7420    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
 7421        self.push_to_selection_history();
 7422        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7423        self.select_next_match_internal(
 7424            &display_map,
 7425            action.replace_newest,
 7426            Some(Autoscroll::newest()),
 7427            cx,
 7428        )?;
 7429        Ok(())
 7430    }
 7431
 7432    pub fn select_previous(
 7433        &mut self,
 7434        action: &SelectPrevious,
 7435        cx: &mut ViewContext<Self>,
 7436    ) -> Result<()> {
 7437        self.push_to_selection_history();
 7438        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7439        let buffer = &display_map.buffer_snapshot;
 7440        let mut selections = self.selections.all::<usize>(cx);
 7441        if let Some(mut select_prev_state) = self.select_prev_state.take() {
 7442            let query = &select_prev_state.query;
 7443            if !select_prev_state.done {
 7444                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 7445                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 7446                let mut next_selected_range = None;
 7447                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
 7448                let bytes_before_last_selection =
 7449                    buffer.reversed_bytes_in_range(0..last_selection.start);
 7450                let bytes_after_first_selection =
 7451                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
 7452                let query_matches = query
 7453                    .stream_find_iter(bytes_before_last_selection)
 7454                    .map(|result| (last_selection.start, result))
 7455                    .chain(
 7456                        query
 7457                            .stream_find_iter(bytes_after_first_selection)
 7458                            .map(|result| (buffer.len(), result)),
 7459                    );
 7460                for (end_offset, query_match) in query_matches {
 7461                    let query_match = query_match.unwrap(); // can only fail due to I/O
 7462                    let offset_range =
 7463                        end_offset - query_match.end()..end_offset - query_match.start();
 7464                    let display_range = offset_range.start.to_display_point(&display_map)
 7465                        ..offset_range.end.to_display_point(&display_map);
 7466
 7467                    if !select_prev_state.wordwise
 7468                        || (!movement::is_inside_word(&display_map, display_range.start)
 7469                            && !movement::is_inside_word(&display_map, display_range.end))
 7470                    {
 7471                        next_selected_range = Some(offset_range);
 7472                        break;
 7473                    }
 7474                }
 7475
 7476                if let Some(next_selected_range) = next_selected_range {
 7477                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
 7478                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 7479                        if action.replace_newest {
 7480                            s.delete(s.newest_anchor().id);
 7481                        }
 7482                        s.insert_range(next_selected_range);
 7483                    });
 7484                } else {
 7485                    select_prev_state.done = true;
 7486                }
 7487            }
 7488
 7489            self.select_prev_state = Some(select_prev_state);
 7490        } else {
 7491            let mut only_carets = true;
 7492            let mut same_text_selected = true;
 7493            let mut selected_text = None;
 7494
 7495            let mut selections_iter = selections.iter().peekable();
 7496            while let Some(selection) = selections_iter.next() {
 7497                if selection.start != selection.end {
 7498                    only_carets = false;
 7499                }
 7500
 7501                if same_text_selected {
 7502                    if selected_text.is_none() {
 7503                        selected_text =
 7504                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 7505                    }
 7506
 7507                    if let Some(next_selection) = selections_iter.peek() {
 7508                        if next_selection.range().len() == selection.range().len() {
 7509                            let next_selected_text = buffer
 7510                                .text_for_range(next_selection.range())
 7511                                .collect::<String>();
 7512                            if Some(next_selected_text) != selected_text {
 7513                                same_text_selected = false;
 7514                                selected_text = None;
 7515                            }
 7516                        } else {
 7517                            same_text_selected = false;
 7518                            selected_text = None;
 7519                        }
 7520                    }
 7521                }
 7522            }
 7523
 7524            if only_carets {
 7525                for selection in &mut selections {
 7526                    let word_range = movement::surrounding_word(
 7527                        &display_map,
 7528                        selection.start.to_display_point(&display_map),
 7529                    );
 7530                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 7531                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 7532                    selection.goal = SelectionGoal::None;
 7533                    selection.reversed = false;
 7534                }
 7535                if selections.len() == 1 {
 7536                    let selection = selections
 7537                        .last()
 7538                        .expect("ensured that there's only one selection");
 7539                    let query = buffer
 7540                        .text_for_range(selection.start..selection.end)
 7541                        .collect::<String>();
 7542                    let is_empty = query.is_empty();
 7543                    let select_state = SelectNextState {
 7544                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
 7545                        wordwise: true,
 7546                        done: is_empty,
 7547                    };
 7548                    self.select_prev_state = Some(select_state);
 7549                } else {
 7550                    self.select_prev_state = None;
 7551                }
 7552
 7553                self.unfold_ranges(
 7554                    selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
 7555                    false,
 7556                    true,
 7557                    cx,
 7558                );
 7559                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 7560                    s.select(selections);
 7561                });
 7562            } else if let Some(selected_text) = selected_text {
 7563                self.select_prev_state = Some(SelectNextState {
 7564                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
 7565                    wordwise: false,
 7566                    done: false,
 7567                });
 7568                self.select_previous(action, cx)?;
 7569            }
 7570        }
 7571        Ok(())
 7572    }
 7573
 7574    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
 7575        let text_layout_details = &self.text_layout_details(cx);
 7576        self.transact(cx, |this, cx| {
 7577            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 7578            let mut edits = Vec::new();
 7579            let mut selection_edit_ranges = Vec::new();
 7580            let mut last_toggled_row = None;
 7581            let snapshot = this.buffer.read(cx).read(cx);
 7582            let empty_str: Arc<str> = "".into();
 7583            let mut suffixes_inserted = Vec::new();
 7584
 7585            fn comment_prefix_range(
 7586                snapshot: &MultiBufferSnapshot,
 7587                row: MultiBufferRow,
 7588                comment_prefix: &str,
 7589                comment_prefix_whitespace: &str,
 7590            ) -> Range<Point> {
 7591                let start = Point::new(row.0, snapshot.indent_size_for_line(row).len);
 7592
 7593                let mut line_bytes = snapshot
 7594                    .bytes_in_range(start..snapshot.max_point())
 7595                    .flatten()
 7596                    .copied();
 7597
 7598                // If this line currently begins with the line comment prefix, then record
 7599                // the range containing the prefix.
 7600                if line_bytes
 7601                    .by_ref()
 7602                    .take(comment_prefix.len())
 7603                    .eq(comment_prefix.bytes())
 7604                {
 7605                    // Include any whitespace that matches the comment prefix.
 7606                    let matching_whitespace_len = line_bytes
 7607                        .zip(comment_prefix_whitespace.bytes())
 7608                        .take_while(|(a, b)| a == b)
 7609                        .count() as u32;
 7610                    let end = Point::new(
 7611                        start.row,
 7612                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
 7613                    );
 7614                    start..end
 7615                } else {
 7616                    start..start
 7617                }
 7618            }
 7619
 7620            fn comment_suffix_range(
 7621                snapshot: &MultiBufferSnapshot,
 7622                row: MultiBufferRow,
 7623                comment_suffix: &str,
 7624                comment_suffix_has_leading_space: bool,
 7625            ) -> Range<Point> {
 7626                let end = Point::new(row.0, snapshot.line_len(row));
 7627                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
 7628
 7629                let mut line_end_bytes = snapshot
 7630                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
 7631                    .flatten()
 7632                    .copied();
 7633
 7634                let leading_space_len = if suffix_start_column > 0
 7635                    && line_end_bytes.next() == Some(b' ')
 7636                    && comment_suffix_has_leading_space
 7637                {
 7638                    1
 7639                } else {
 7640                    0
 7641                };
 7642
 7643                // If this line currently begins with the line comment prefix, then record
 7644                // the range containing the prefix.
 7645                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
 7646                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
 7647                    start..end
 7648                } else {
 7649                    end..end
 7650                }
 7651            }
 7652
 7653            // TODO: Handle selections that cross excerpts
 7654            for selection in &mut selections {
 7655                let start_column = snapshot
 7656                    .indent_size_for_line(MultiBufferRow(selection.start.row))
 7657                    .len;
 7658                let language = if let Some(language) =
 7659                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
 7660                {
 7661                    language
 7662                } else {
 7663                    continue;
 7664                };
 7665
 7666                selection_edit_ranges.clear();
 7667
 7668                // If multiple selections contain a given row, avoid processing that
 7669                // row more than once.
 7670                let mut start_row = MultiBufferRow(selection.start.row);
 7671                if last_toggled_row == Some(start_row) {
 7672                    start_row = start_row.next_row();
 7673                }
 7674                let end_row =
 7675                    if selection.end.row > selection.start.row && selection.end.column == 0 {
 7676                        MultiBufferRow(selection.end.row - 1)
 7677                    } else {
 7678                        MultiBufferRow(selection.end.row)
 7679                    };
 7680                last_toggled_row = Some(end_row);
 7681
 7682                if start_row > end_row {
 7683                    continue;
 7684                }
 7685
 7686                // If the language has line comments, toggle those.
 7687                let full_comment_prefixes = language.line_comment_prefixes();
 7688                if !full_comment_prefixes.is_empty() {
 7689                    let first_prefix = full_comment_prefixes
 7690                        .first()
 7691                        .expect("prefixes is non-empty");
 7692                    let prefix_trimmed_lengths = full_comment_prefixes
 7693                        .iter()
 7694                        .map(|p| p.trim_end_matches(' ').len())
 7695                        .collect::<SmallVec<[usize; 4]>>();
 7696
 7697                    let mut all_selection_lines_are_comments = true;
 7698
 7699                    for row in start_row.0..=end_row.0 {
 7700                        let row = MultiBufferRow(row);
 7701                        if start_row < end_row && snapshot.is_line_blank(row) {
 7702                            continue;
 7703                        }
 7704
 7705                        let prefix_range = full_comment_prefixes
 7706                            .iter()
 7707                            .zip(prefix_trimmed_lengths.iter().copied())
 7708                            .map(|(prefix, trimmed_prefix_len)| {
 7709                                comment_prefix_range(
 7710                                    snapshot.deref(),
 7711                                    row,
 7712                                    &prefix[..trimmed_prefix_len],
 7713                                    &prefix[trimmed_prefix_len..],
 7714                                )
 7715                            })
 7716                            .max_by_key(|range| range.end.column - range.start.column)
 7717                            .expect("prefixes is non-empty");
 7718
 7719                        if prefix_range.is_empty() {
 7720                            all_selection_lines_are_comments = false;
 7721                        }
 7722
 7723                        selection_edit_ranges.push(prefix_range);
 7724                    }
 7725
 7726                    if all_selection_lines_are_comments {
 7727                        edits.extend(
 7728                            selection_edit_ranges
 7729                                .iter()
 7730                                .cloned()
 7731                                .map(|range| (range, empty_str.clone())),
 7732                        );
 7733                    } else {
 7734                        let min_column = selection_edit_ranges
 7735                            .iter()
 7736                            .map(|range| range.start.column)
 7737                            .min()
 7738                            .unwrap_or(0);
 7739                        edits.extend(selection_edit_ranges.iter().map(|range| {
 7740                            let position = Point::new(range.start.row, min_column);
 7741                            (position..position, first_prefix.clone())
 7742                        }));
 7743                    }
 7744                } else if let Some((full_comment_prefix, comment_suffix)) =
 7745                    language.block_comment_delimiters()
 7746                {
 7747                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 7748                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 7749                    let prefix_range = comment_prefix_range(
 7750                        snapshot.deref(),
 7751                        start_row,
 7752                        comment_prefix,
 7753                        comment_prefix_whitespace,
 7754                    );
 7755                    let suffix_range = comment_suffix_range(
 7756                        snapshot.deref(),
 7757                        end_row,
 7758                        comment_suffix.trim_start_matches(' '),
 7759                        comment_suffix.starts_with(' '),
 7760                    );
 7761
 7762                    if prefix_range.is_empty() || suffix_range.is_empty() {
 7763                        edits.push((
 7764                            prefix_range.start..prefix_range.start,
 7765                            full_comment_prefix.clone(),
 7766                        ));
 7767                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
 7768                        suffixes_inserted.push((end_row, comment_suffix.len()));
 7769                    } else {
 7770                        edits.push((prefix_range, empty_str.clone()));
 7771                        edits.push((suffix_range, empty_str.clone()));
 7772                    }
 7773                } else {
 7774                    continue;
 7775                }
 7776            }
 7777
 7778            drop(snapshot);
 7779            this.buffer.update(cx, |buffer, cx| {
 7780                buffer.edit(edits, None, cx);
 7781            });
 7782
 7783            // Adjust selections so that they end before any comment suffixes that
 7784            // were inserted.
 7785            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
 7786            let mut selections = this.selections.all::<Point>(cx);
 7787            let snapshot = this.buffer.read(cx).read(cx);
 7788            for selection in &mut selections {
 7789                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
 7790                    match row.cmp(&MultiBufferRow(selection.end.row)) {
 7791                        Ordering::Less => {
 7792                            suffixes_inserted.next();
 7793                            continue;
 7794                        }
 7795                        Ordering::Greater => break,
 7796                        Ordering::Equal => {
 7797                            if selection.end.column == snapshot.line_len(row) {
 7798                                if selection.is_empty() {
 7799                                    selection.start.column -= suffix_len as u32;
 7800                                }
 7801                                selection.end.column -= suffix_len as u32;
 7802                            }
 7803                            break;
 7804                        }
 7805                    }
 7806                }
 7807            }
 7808
 7809            drop(snapshot);
 7810            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 7811
 7812            let selections = this.selections.all::<Point>(cx);
 7813            let selections_on_single_row = selections.windows(2).all(|selections| {
 7814                selections[0].start.row == selections[1].start.row
 7815                    && selections[0].end.row == selections[1].end.row
 7816                    && selections[0].start.row == selections[0].end.row
 7817            });
 7818            let selections_selecting = selections
 7819                .iter()
 7820                .any(|selection| selection.start != selection.end);
 7821            let advance_downwards = action.advance_downwards
 7822                && selections_on_single_row
 7823                && !selections_selecting
 7824                && this.mode != EditorMode::SingleLine;
 7825
 7826            if advance_downwards {
 7827                let snapshot = this.buffer.read(cx).snapshot(cx);
 7828
 7829                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7830                    s.move_cursors_with(|display_snapshot, display_point, _| {
 7831                        let mut point = display_point.to_point(display_snapshot);
 7832                        point.row += 1;
 7833                        point = snapshot.clip_point(point, Bias::Left);
 7834                        let display_point = point.to_display_point(display_snapshot);
 7835                        let goal = SelectionGoal::HorizontalPosition(
 7836                            display_snapshot
 7837                                .x_for_display_point(display_point, &text_layout_details)
 7838                                .into(),
 7839                        );
 7840                        (display_point, goal)
 7841                    })
 7842                });
 7843            }
 7844        });
 7845    }
 7846
 7847    pub fn select_larger_syntax_node(
 7848        &mut self,
 7849        _: &SelectLargerSyntaxNode,
 7850        cx: &mut ViewContext<Self>,
 7851    ) {
 7852        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7853        let buffer = self.buffer.read(cx).snapshot(cx);
 7854        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 7855
 7856        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7857        let mut selected_larger_node = false;
 7858        let new_selections = old_selections
 7859            .iter()
 7860            .map(|selection| {
 7861                let old_range = selection.start..selection.end;
 7862                let mut new_range = old_range.clone();
 7863                while let Some(containing_range) =
 7864                    buffer.range_for_syntax_ancestor(new_range.clone())
 7865                {
 7866                    new_range = containing_range;
 7867                    if !display_map.intersects_fold(new_range.start)
 7868                        && !display_map.intersects_fold(new_range.end)
 7869                    {
 7870                        break;
 7871                    }
 7872                }
 7873
 7874                selected_larger_node |= new_range != old_range;
 7875                Selection {
 7876                    id: selection.id,
 7877                    start: new_range.start,
 7878                    end: new_range.end,
 7879                    goal: SelectionGoal::None,
 7880                    reversed: selection.reversed,
 7881                }
 7882            })
 7883            .collect::<Vec<_>>();
 7884
 7885        if selected_larger_node {
 7886            stack.push(old_selections);
 7887            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7888                s.select(new_selections);
 7889            });
 7890        }
 7891        self.select_larger_syntax_node_stack = stack;
 7892    }
 7893
 7894    pub fn select_smaller_syntax_node(
 7895        &mut self,
 7896        _: &SelectSmallerSyntaxNode,
 7897        cx: &mut ViewContext<Self>,
 7898    ) {
 7899        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7900        if let Some(selections) = stack.pop() {
 7901            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7902                s.select(selections.to_vec());
 7903            });
 7904        }
 7905        self.select_larger_syntax_node_stack = stack;
 7906    }
 7907
 7908    fn refresh_runnables(&mut self, cx: &mut ViewContext<Self>) -> Task<()> {
 7909        let project = self.project.clone();
 7910        cx.spawn(|this, mut cx| async move {
 7911            let Ok(display_snapshot) = this.update(&mut cx, |this, cx| {
 7912                this.display_map.update(cx, |map, cx| map.snapshot(cx))
 7913            }) else {
 7914                return;
 7915            };
 7916
 7917            let Some(project) = project else {
 7918                return;
 7919            };
 7920
 7921            let hide_runnables = project
 7922                .update(&mut cx, |project, cx| {
 7923                    // Do not display any test indicators in non-dev server remote projects.
 7924                    project.is_remote() && project.ssh_connection_string(cx).is_none()
 7925                })
 7926                .unwrap_or(true);
 7927            if hide_runnables {
 7928                return;
 7929            }
 7930            let new_rows =
 7931                cx.background_executor()
 7932                    .spawn({
 7933                        let snapshot = display_snapshot.clone();
 7934                        async move {
 7935                            Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
 7936                        }
 7937                    })
 7938                    .await;
 7939            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
 7940
 7941            this.update(&mut cx, |this, _| {
 7942                this.clear_tasks();
 7943                for (key, value) in rows {
 7944                    this.insert_tasks(key, value);
 7945                }
 7946            })
 7947            .ok();
 7948        })
 7949    }
 7950    fn fetch_runnable_ranges(
 7951        snapshot: &DisplaySnapshot,
 7952        range: Range<Anchor>,
 7953    ) -> Vec<language::RunnableRange> {
 7954        snapshot.buffer_snapshot.runnable_ranges(range).collect()
 7955    }
 7956
 7957    fn runnable_rows(
 7958        project: Model<Project>,
 7959        snapshot: DisplaySnapshot,
 7960        runnable_ranges: Vec<RunnableRange>,
 7961        mut cx: AsyncWindowContext,
 7962    ) -> Vec<((BufferId, u32), RunnableTasks)> {
 7963        runnable_ranges
 7964            .into_iter()
 7965            .filter_map(|mut runnable| {
 7966                let tasks = cx
 7967                    .update(|cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
 7968                    .ok()?;
 7969                if tasks.is_empty() {
 7970                    return None;
 7971                }
 7972
 7973                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
 7974
 7975                let row = snapshot
 7976                    .buffer_snapshot
 7977                    .buffer_line_for_row(MultiBufferRow(point.row))?
 7978                    .1
 7979                    .start
 7980                    .row;
 7981
 7982                let context_range =
 7983                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
 7984                Some((
 7985                    (runnable.buffer_id, row),
 7986                    RunnableTasks {
 7987                        templates: tasks,
 7988                        offset: MultiBufferOffset(runnable.run_range.start),
 7989                        context_range,
 7990                        column: point.column,
 7991                        extra_variables: runnable.extra_captures,
 7992                    },
 7993                ))
 7994            })
 7995            .collect()
 7996    }
 7997
 7998    fn templates_with_tags(
 7999        project: &Model<Project>,
 8000        runnable: &mut Runnable,
 8001        cx: &WindowContext<'_>,
 8002    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
 8003        let (inventory, worktree_id) = project.read_with(cx, |project, cx| {
 8004            let worktree_id = project
 8005                .buffer_for_id(runnable.buffer)
 8006                .and_then(|buffer| buffer.read(cx).file())
 8007                .map(|file| WorktreeId::from_usize(file.worktree_id()));
 8008
 8009            (project.task_inventory().clone(), worktree_id)
 8010        });
 8011
 8012        let inventory = inventory.read(cx);
 8013        let tags = mem::take(&mut runnable.tags);
 8014        let mut tags: Vec<_> = tags
 8015            .into_iter()
 8016            .flat_map(|tag| {
 8017                let tag = tag.0.clone();
 8018                inventory
 8019                    .list_tasks(Some(runnable.language.clone()), worktree_id)
 8020                    .into_iter()
 8021                    .filter(move |(_, template)| {
 8022                        template.tags.iter().any(|source_tag| source_tag == &tag)
 8023                    })
 8024            })
 8025            .sorted_by_key(|(kind, _)| kind.to_owned())
 8026            .collect();
 8027        if let Some((leading_tag_source, _)) = tags.first() {
 8028            // Strongest source wins; if we have worktree tag binding, prefer that to
 8029            // global and language bindings;
 8030            // if we have a global binding, prefer that to language binding.
 8031            let first_mismatch = tags
 8032                .iter()
 8033                .position(|(tag_source, _)| tag_source != leading_tag_source);
 8034            if let Some(index) = first_mismatch {
 8035                tags.truncate(index);
 8036            }
 8037        }
 8038
 8039        tags
 8040    }
 8041
 8042    pub fn move_to_enclosing_bracket(
 8043        &mut self,
 8044        _: &MoveToEnclosingBracket,
 8045        cx: &mut ViewContext<Self>,
 8046    ) {
 8047        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8048            s.move_offsets_with(|snapshot, selection| {
 8049                let Some(enclosing_bracket_ranges) =
 8050                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
 8051                else {
 8052                    return;
 8053                };
 8054
 8055                let mut best_length = usize::MAX;
 8056                let mut best_inside = false;
 8057                let mut best_in_bracket_range = false;
 8058                let mut best_destination = None;
 8059                for (open, close) in enclosing_bracket_ranges {
 8060                    let close = close.to_inclusive();
 8061                    let length = close.end() - open.start;
 8062                    let inside = selection.start >= open.end && selection.end <= *close.start();
 8063                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
 8064                        || close.contains(&selection.head());
 8065
 8066                    // If best is next to a bracket and current isn't, skip
 8067                    if !in_bracket_range && best_in_bracket_range {
 8068                        continue;
 8069                    }
 8070
 8071                    // Prefer smaller lengths unless best is inside and current isn't
 8072                    if length > best_length && (best_inside || !inside) {
 8073                        continue;
 8074                    }
 8075
 8076                    best_length = length;
 8077                    best_inside = inside;
 8078                    best_in_bracket_range = in_bracket_range;
 8079                    best_destination = Some(
 8080                        if close.contains(&selection.start) && close.contains(&selection.end) {
 8081                            if inside {
 8082                                open.end
 8083                            } else {
 8084                                open.start
 8085                            }
 8086                        } else {
 8087                            if inside {
 8088                                *close.start()
 8089                            } else {
 8090                                *close.end()
 8091                            }
 8092                        },
 8093                    );
 8094                }
 8095
 8096                if let Some(destination) = best_destination {
 8097                    selection.collapse_to(destination, SelectionGoal::None);
 8098                }
 8099            })
 8100        });
 8101    }
 8102
 8103    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 8104        self.end_selection(cx);
 8105        self.selection_history.mode = SelectionHistoryMode::Undoing;
 8106        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 8107            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 8108            self.select_next_state = entry.select_next_state;
 8109            self.select_prev_state = entry.select_prev_state;
 8110            self.add_selections_state = entry.add_selections_state;
 8111            self.request_autoscroll(Autoscroll::newest(), cx);
 8112        }
 8113        self.selection_history.mode = SelectionHistoryMode::Normal;
 8114    }
 8115
 8116    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 8117        self.end_selection(cx);
 8118        self.selection_history.mode = SelectionHistoryMode::Redoing;
 8119        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 8120            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 8121            self.select_next_state = entry.select_next_state;
 8122            self.select_prev_state = entry.select_prev_state;
 8123            self.add_selections_state = entry.add_selections_state;
 8124            self.request_autoscroll(Autoscroll::newest(), cx);
 8125        }
 8126        self.selection_history.mode = SelectionHistoryMode::Normal;
 8127    }
 8128
 8129    pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext<Self>) {
 8130        let selections = self.selections.disjoint_anchors();
 8131
 8132        let lines = if action.lines == 0 { 3 } else { action.lines };
 8133
 8134        self.buffer.update(cx, |buffer, cx| {
 8135            buffer.expand_excerpts(
 8136                selections
 8137                    .into_iter()
 8138                    .map(|selection| selection.head().excerpt_id)
 8139                    .dedup(),
 8140                lines,
 8141                cx,
 8142            )
 8143        })
 8144    }
 8145
 8146    pub fn expand_excerpt(&mut self, excerpt: ExcerptId, cx: &mut ViewContext<Self>) {
 8147        self.buffer
 8148            .update(cx, |buffer, cx| buffer.expand_excerpts([excerpt], 3, cx))
 8149    }
 8150
 8151    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
 8152        self.go_to_diagnostic_impl(Direction::Next, cx)
 8153    }
 8154
 8155    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 8156        self.go_to_diagnostic_impl(Direction::Prev, cx)
 8157    }
 8158
 8159    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 8160        let buffer = self.buffer.read(cx).snapshot(cx);
 8161        let selection = self.selections.newest::<usize>(cx);
 8162
 8163        // If there is an active Diagnostic Popover jump to its diagnostic instead.
 8164        if direction == Direction::Next {
 8165            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
 8166                let (group_id, jump_to) = popover.activation_info();
 8167                if self.activate_diagnostics(group_id, cx) {
 8168                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8169                        let mut new_selection = s.newest_anchor().clone();
 8170                        new_selection.collapse_to(jump_to, SelectionGoal::None);
 8171                        s.select_anchors(vec![new_selection.clone()]);
 8172                    });
 8173                }
 8174                return;
 8175            }
 8176        }
 8177
 8178        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 8179            active_diagnostics
 8180                .primary_range
 8181                .to_offset(&buffer)
 8182                .to_inclusive()
 8183        });
 8184        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 8185            if active_primary_range.contains(&selection.head()) {
 8186                *active_primary_range.start()
 8187            } else {
 8188                selection.head()
 8189            }
 8190        } else {
 8191            selection.head()
 8192        };
 8193        let snapshot = self.snapshot(cx);
 8194        loop {
 8195            let diagnostics = if direction == Direction::Prev {
 8196                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 8197            } else {
 8198                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 8199            }
 8200            .filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
 8201            let group = diagnostics
 8202                // relies on diagnostics_in_range to return diagnostics with the same starting range to
 8203                // be sorted in a stable way
 8204                // skip until we are at current active diagnostic, if it exists
 8205                .skip_while(|entry| {
 8206                    (match direction {
 8207                        Direction::Prev => entry.range.start >= search_start,
 8208                        Direction::Next => entry.range.start <= search_start,
 8209                    }) && self
 8210                        .active_diagnostics
 8211                        .as_ref()
 8212                        .is_some_and(|a| a.group_id != entry.diagnostic.group_id)
 8213                })
 8214                .find_map(|entry| {
 8215                    if entry.diagnostic.is_primary
 8216                        && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 8217                        && !entry.range.is_empty()
 8218                        // if we match with the active diagnostic, skip it
 8219                        && Some(entry.diagnostic.group_id)
 8220                            != self.active_diagnostics.as_ref().map(|d| d.group_id)
 8221                    {
 8222                        Some((entry.range, entry.diagnostic.group_id))
 8223                    } else {
 8224                        None
 8225                    }
 8226                });
 8227
 8228            if let Some((primary_range, group_id)) = group {
 8229                if self.activate_diagnostics(group_id, cx) {
 8230                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8231                        s.select(vec![Selection {
 8232                            id: selection.id,
 8233                            start: primary_range.start,
 8234                            end: primary_range.start,
 8235                            reversed: false,
 8236                            goal: SelectionGoal::None,
 8237                        }]);
 8238                    });
 8239                }
 8240                break;
 8241            } else {
 8242                // Cycle around to the start of the buffer, potentially moving back to the start of
 8243                // the currently active diagnostic.
 8244                active_primary_range.take();
 8245                if direction == Direction::Prev {
 8246                    if search_start == buffer.len() {
 8247                        break;
 8248                    } else {
 8249                        search_start = buffer.len();
 8250                    }
 8251                } else if search_start == 0 {
 8252                    break;
 8253                } else {
 8254                    search_start = 0;
 8255                }
 8256            }
 8257        }
 8258    }
 8259
 8260    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
 8261        let snapshot = self
 8262            .display_map
 8263            .update(cx, |display_map, cx| display_map.snapshot(cx));
 8264        let selection = self.selections.newest::<Point>(cx);
 8265
 8266        if !self.seek_in_direction(
 8267            &snapshot,
 8268            selection.head(),
 8269            false,
 8270            snapshot.buffer_snapshot.git_diff_hunks_in_range(
 8271                MultiBufferRow(selection.head().row + 1)..MultiBufferRow::MAX,
 8272            ),
 8273            cx,
 8274        ) {
 8275            let wrapped_point = Point::zero();
 8276            self.seek_in_direction(
 8277                &snapshot,
 8278                wrapped_point,
 8279                true,
 8280                snapshot.buffer_snapshot.git_diff_hunks_in_range(
 8281                    MultiBufferRow(wrapped_point.row + 1)..MultiBufferRow::MAX,
 8282                ),
 8283                cx,
 8284            );
 8285        }
 8286    }
 8287
 8288    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
 8289        let snapshot = self
 8290            .display_map
 8291            .update(cx, |display_map, cx| display_map.snapshot(cx));
 8292        let selection = self.selections.newest::<Point>(cx);
 8293
 8294        if !self.seek_in_direction(
 8295            &snapshot,
 8296            selection.head(),
 8297            false,
 8298            snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
 8299                MultiBufferRow(0)..MultiBufferRow(selection.head().row),
 8300            ),
 8301            cx,
 8302        ) {
 8303            let wrapped_point = snapshot.buffer_snapshot.max_point();
 8304            self.seek_in_direction(
 8305                &snapshot,
 8306                wrapped_point,
 8307                true,
 8308                snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
 8309                    MultiBufferRow(0)..MultiBufferRow(wrapped_point.row),
 8310                ),
 8311                cx,
 8312            );
 8313        }
 8314    }
 8315
 8316    fn seek_in_direction(
 8317        &mut self,
 8318        snapshot: &DisplaySnapshot,
 8319        initial_point: Point,
 8320        is_wrapped: bool,
 8321        hunks: impl Iterator<Item = DiffHunk<MultiBufferRow>>,
 8322        cx: &mut ViewContext<Editor>,
 8323    ) -> bool {
 8324        let display_point = initial_point.to_display_point(snapshot);
 8325        let mut hunks = hunks
 8326            .map(|hunk| diff_hunk_to_display(&hunk, &snapshot))
 8327            .filter(|hunk| {
 8328                if is_wrapped {
 8329                    true
 8330                } else {
 8331                    !hunk.contains_display_row(display_point.row())
 8332                }
 8333            })
 8334            .dedup();
 8335
 8336        if let Some(hunk) = hunks.next() {
 8337            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8338                let row = hunk.start_display_row();
 8339                let point = DisplayPoint::new(row, 0);
 8340                s.select_display_ranges([point..point]);
 8341            });
 8342
 8343            true
 8344        } else {
 8345            false
 8346        }
 8347    }
 8348
 8349    pub fn go_to_definition(
 8350        &mut self,
 8351        _: &GoToDefinition,
 8352        cx: &mut ViewContext<Self>,
 8353    ) -> Task<Result<bool>> {
 8354        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx)
 8355    }
 8356
 8357    pub fn go_to_implementation(
 8358        &mut self,
 8359        _: &GoToImplementation,
 8360        cx: &mut ViewContext<Self>,
 8361    ) -> Task<Result<bool>> {
 8362        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx)
 8363    }
 8364
 8365    pub fn go_to_implementation_split(
 8366        &mut self,
 8367        _: &GoToImplementationSplit,
 8368        cx: &mut ViewContext<Self>,
 8369    ) -> Task<Result<bool>> {
 8370        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx)
 8371    }
 8372
 8373    pub fn go_to_type_definition(
 8374        &mut self,
 8375        _: &GoToTypeDefinition,
 8376        cx: &mut ViewContext<Self>,
 8377    ) -> Task<Result<bool>> {
 8378        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx)
 8379    }
 8380
 8381    pub fn go_to_definition_split(
 8382        &mut self,
 8383        _: &GoToDefinitionSplit,
 8384        cx: &mut ViewContext<Self>,
 8385    ) -> Task<Result<bool>> {
 8386        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx)
 8387    }
 8388
 8389    pub fn go_to_type_definition_split(
 8390        &mut self,
 8391        _: &GoToTypeDefinitionSplit,
 8392        cx: &mut ViewContext<Self>,
 8393    ) -> Task<Result<bool>> {
 8394        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx)
 8395    }
 8396
 8397    fn go_to_definition_of_kind(
 8398        &mut self,
 8399        kind: GotoDefinitionKind,
 8400        split: bool,
 8401        cx: &mut ViewContext<Self>,
 8402    ) -> Task<Result<bool>> {
 8403        let Some(workspace) = self.workspace() else {
 8404            return Task::ready(Ok(false));
 8405        };
 8406        let buffer = self.buffer.read(cx);
 8407        let head = self.selections.newest::<usize>(cx).head();
 8408        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 8409            text_anchor
 8410        } else {
 8411            return Task::ready(Ok(false));
 8412        };
 8413
 8414        let project = workspace.read(cx).project().clone();
 8415        let definitions = project.update(cx, |project, cx| match kind {
 8416            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
 8417            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
 8418            GotoDefinitionKind::Implementation => project.implementation(&buffer, head, cx),
 8419        });
 8420
 8421        cx.spawn(|editor, mut cx| async move {
 8422            let definitions = definitions.await?;
 8423            let navigated = editor
 8424                .update(&mut cx, |editor, cx| {
 8425                    editor.navigate_to_hover_links(
 8426                        Some(kind),
 8427                        definitions
 8428                            .into_iter()
 8429                            .filter(|location| {
 8430                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
 8431                            })
 8432                            .map(HoverLink::Text)
 8433                            .collect::<Vec<_>>(),
 8434                        split,
 8435                        cx,
 8436                    )
 8437                })?
 8438                .await?;
 8439            anyhow::Ok(navigated)
 8440        })
 8441    }
 8442
 8443    pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext<Self>) {
 8444        let position = self.selections.newest_anchor().head();
 8445        let Some((buffer, buffer_position)) =
 8446            self.buffer.read(cx).text_anchor_for_position(position, cx)
 8447        else {
 8448            return;
 8449        };
 8450
 8451        cx.spawn(|editor, mut cx| async move {
 8452            if let Some((_, url)) = find_url(&buffer, buffer_position, cx.clone()) {
 8453                editor.update(&mut cx, |_, cx| {
 8454                    cx.open_url(&url);
 8455                })
 8456            } else {
 8457                Ok(())
 8458            }
 8459        })
 8460        .detach();
 8461    }
 8462
 8463    pub(crate) fn navigate_to_hover_links(
 8464        &mut self,
 8465        kind: Option<GotoDefinitionKind>,
 8466        mut definitions: Vec<HoverLink>,
 8467        split: bool,
 8468        cx: &mut ViewContext<Editor>,
 8469    ) -> Task<Result<bool>> {
 8470        // If there is one definition, just open it directly
 8471        if definitions.len() == 1 {
 8472            let definition = definitions.pop().unwrap();
 8473            let target_task = match definition {
 8474                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 8475                HoverLink::InlayHint(lsp_location, server_id) => {
 8476                    self.compute_target_location(lsp_location, server_id, cx)
 8477                }
 8478                HoverLink::Url(url) => {
 8479                    cx.open_url(&url);
 8480                    Task::ready(Ok(None))
 8481                }
 8482            };
 8483            cx.spawn(|editor, mut cx| async move {
 8484                let target = target_task.await.context("target resolution task")?;
 8485                if let Some(target) = target {
 8486                    editor.update(&mut cx, |editor, cx| {
 8487                        let Some(workspace) = editor.workspace() else {
 8488                            return false;
 8489                        };
 8490                        let pane = workspace.read(cx).active_pane().clone();
 8491
 8492                        let range = target.range.to_offset(target.buffer.read(cx));
 8493                        let range = editor.range_for_match(&range);
 8494
 8495                        /// If select range has more than one line, we
 8496                        /// just point the cursor to range.start.
 8497                        fn check_multiline_range(
 8498                            buffer: &Buffer,
 8499                            range: Range<usize>,
 8500                        ) -> Range<usize> {
 8501                            if buffer.offset_to_point(range.start).row
 8502                                == buffer.offset_to_point(range.end).row
 8503                            {
 8504                                range
 8505                            } else {
 8506                                range.start..range.start
 8507                            }
 8508                        }
 8509
 8510                        if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
 8511                            let buffer = target.buffer.read(cx);
 8512                            let range = check_multiline_range(buffer, range);
 8513                            editor.change_selections(Some(Autoscroll::focused()), cx, |s| {
 8514                                s.select_ranges([range]);
 8515                            });
 8516                        } else {
 8517                            cx.window_context().defer(move |cx| {
 8518                                let target_editor: View<Self> =
 8519                                    workspace.update(cx, |workspace, cx| {
 8520                                        let pane = if split {
 8521                                            workspace.adjacent_pane(cx)
 8522                                        } else {
 8523                                            workspace.active_pane().clone()
 8524                                        };
 8525
 8526                                        workspace.open_project_item(pane, target.buffer.clone(), cx)
 8527                                    });
 8528                                target_editor.update(cx, |target_editor, cx| {
 8529                                    // When selecting a definition in a different buffer, disable the nav history
 8530                                    // to avoid creating a history entry at the previous cursor location.
 8531                                    pane.update(cx, |pane, _| pane.disable_history());
 8532                                    let buffer = target.buffer.read(cx);
 8533                                    let range = check_multiline_range(buffer, range);
 8534                                    target_editor.change_selections(
 8535                                        Some(Autoscroll::focused()),
 8536                                        cx,
 8537                                        |s| {
 8538                                            s.select_ranges([range]);
 8539                                        },
 8540                                    );
 8541                                    pane.update(cx, |pane, _| pane.enable_history());
 8542                                });
 8543                            });
 8544                        }
 8545                        true
 8546                    })
 8547                } else {
 8548                    Ok(false)
 8549                }
 8550            })
 8551        } else if !definitions.is_empty() {
 8552            let replica_id = self.replica_id(cx);
 8553            cx.spawn(|editor, mut cx| async move {
 8554                let (title, location_tasks, workspace) = editor
 8555                    .update(&mut cx, |editor, cx| {
 8556                        let tab_kind = match kind {
 8557                            Some(GotoDefinitionKind::Implementation) => "Implementations",
 8558                            _ => "Definitions",
 8559                        };
 8560                        let title = definitions
 8561                            .iter()
 8562                            .find_map(|definition| match definition {
 8563                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
 8564                                    let buffer = origin.buffer.read(cx);
 8565                                    format!(
 8566                                        "{} for {}",
 8567                                        tab_kind,
 8568                                        buffer
 8569                                            .text_for_range(origin.range.clone())
 8570                                            .collect::<String>()
 8571                                    )
 8572                                }),
 8573                                HoverLink::InlayHint(_, _) => None,
 8574                                HoverLink::Url(_) => None,
 8575                            })
 8576                            .unwrap_or(tab_kind.to_string());
 8577                        let location_tasks = definitions
 8578                            .into_iter()
 8579                            .map(|definition| match definition {
 8580                                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 8581                                HoverLink::InlayHint(lsp_location, server_id) => {
 8582                                    editor.compute_target_location(lsp_location, server_id, cx)
 8583                                }
 8584                                HoverLink::Url(_) => Task::ready(Ok(None)),
 8585                            })
 8586                            .collect::<Vec<_>>();
 8587                        (title, location_tasks, editor.workspace().clone())
 8588                    })
 8589                    .context("location tasks preparation")?;
 8590
 8591                let locations = futures::future::join_all(location_tasks)
 8592                    .await
 8593                    .into_iter()
 8594                    .filter_map(|location| location.transpose())
 8595                    .collect::<Result<_>>()
 8596                    .context("location tasks")?;
 8597
 8598                let Some(workspace) = workspace else {
 8599                    return Ok(false);
 8600                };
 8601                let opened = workspace
 8602                    .update(&mut cx, |workspace, cx| {
 8603                        Self::open_locations_in_multibuffer(
 8604                            workspace, locations, replica_id, title, split, cx,
 8605                        )
 8606                    })
 8607                    .ok();
 8608
 8609                anyhow::Ok(opened.is_some())
 8610            })
 8611        } else {
 8612            Task::ready(Ok(false))
 8613        }
 8614    }
 8615
 8616    fn compute_target_location(
 8617        &self,
 8618        lsp_location: lsp::Location,
 8619        server_id: LanguageServerId,
 8620        cx: &mut ViewContext<Editor>,
 8621    ) -> Task<anyhow::Result<Option<Location>>> {
 8622        let Some(project) = self.project.clone() else {
 8623            return Task::Ready(Some(Ok(None)));
 8624        };
 8625
 8626        cx.spawn(move |editor, mut cx| async move {
 8627            let location_task = editor.update(&mut cx, |editor, cx| {
 8628                project.update(cx, |project, cx| {
 8629                    let language_server_name =
 8630                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
 8631                            project
 8632                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 8633                                .map(|(lsp_adapter, _)| lsp_adapter.name.clone())
 8634                        });
 8635                    language_server_name.map(|language_server_name| {
 8636                        project.open_local_buffer_via_lsp(
 8637                            lsp_location.uri.clone(),
 8638                            server_id,
 8639                            language_server_name,
 8640                            cx,
 8641                        )
 8642                    })
 8643                })
 8644            })?;
 8645            let location = match location_task {
 8646                Some(task) => Some({
 8647                    let target_buffer_handle = task.await.context("open local buffer")?;
 8648                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
 8649                        let target_start = target_buffer
 8650                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 8651                        let target_end = target_buffer
 8652                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 8653                        target_buffer.anchor_after(target_start)
 8654                            ..target_buffer.anchor_before(target_end)
 8655                    })?;
 8656                    Location {
 8657                        buffer: target_buffer_handle,
 8658                        range,
 8659                    }
 8660                }),
 8661                None => None,
 8662            };
 8663            Ok(location)
 8664        })
 8665    }
 8666
 8667    pub fn find_all_references(
 8668        &mut self,
 8669        _: &FindAllReferences,
 8670        cx: &mut ViewContext<Self>,
 8671    ) -> Option<Task<Result<()>>> {
 8672        let multi_buffer = self.buffer.read(cx);
 8673        let selection = self.selections.newest::<usize>(cx);
 8674        let head = selection.head();
 8675
 8676        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 8677        let head_anchor = multi_buffer_snapshot.anchor_at(
 8678            head,
 8679            if head < selection.tail() {
 8680                Bias::Right
 8681            } else {
 8682                Bias::Left
 8683            },
 8684        );
 8685
 8686        match self
 8687            .find_all_references_task_sources
 8688            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
 8689        {
 8690            Ok(_) => {
 8691                log::info!(
 8692                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
 8693                );
 8694                return None;
 8695            }
 8696            Err(i) => {
 8697                self.find_all_references_task_sources.insert(i, head_anchor);
 8698            }
 8699        }
 8700
 8701        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
 8702        let replica_id = self.replica_id(cx);
 8703        let workspace = self.workspace()?;
 8704        let project = workspace.read(cx).project().clone();
 8705        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
 8706        Some(cx.spawn(|editor, mut cx| async move {
 8707            let _cleanup = defer({
 8708                let mut cx = cx.clone();
 8709                move || {
 8710                    let _ = editor.update(&mut cx, |editor, _| {
 8711                        if let Ok(i) =
 8712                            editor
 8713                                .find_all_references_task_sources
 8714                                .binary_search_by(|anchor| {
 8715                                    anchor.cmp(&head_anchor, &multi_buffer_snapshot)
 8716                                })
 8717                        {
 8718                            editor.find_all_references_task_sources.remove(i);
 8719                        }
 8720                    });
 8721                }
 8722            });
 8723
 8724            let locations = references.await?;
 8725            if locations.is_empty() {
 8726                return anyhow::Ok(());
 8727            }
 8728
 8729            workspace.update(&mut cx, |workspace, cx| {
 8730                let title = locations
 8731                    .first()
 8732                    .as_ref()
 8733                    .map(|location| {
 8734                        let buffer = location.buffer.read(cx);
 8735                        format!(
 8736                            "References to `{}`",
 8737                            buffer
 8738                                .text_for_range(location.range.clone())
 8739                                .collect::<String>()
 8740                        )
 8741                    })
 8742                    .unwrap();
 8743                Self::open_locations_in_multibuffer(
 8744                    workspace, locations, replica_id, title, false, cx,
 8745                );
 8746            })
 8747        }))
 8748    }
 8749
 8750    /// Opens a multibuffer with the given project locations in it
 8751    pub fn open_locations_in_multibuffer(
 8752        workspace: &mut Workspace,
 8753        mut locations: Vec<Location>,
 8754        replica_id: ReplicaId,
 8755        title: String,
 8756        split: bool,
 8757        cx: &mut ViewContext<Workspace>,
 8758    ) {
 8759        // If there are multiple definitions, open them in a multibuffer
 8760        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
 8761        let mut locations = locations.into_iter().peekable();
 8762        let mut ranges_to_highlight = Vec::new();
 8763        let capability = workspace.project().read(cx).capability();
 8764
 8765        let excerpt_buffer = cx.new_model(|cx| {
 8766            let mut multibuffer = MultiBuffer::new(replica_id, capability);
 8767            while let Some(location) = locations.next() {
 8768                let buffer = location.buffer.read(cx);
 8769                let mut ranges_for_buffer = Vec::new();
 8770                let range = location.range.to_offset(buffer);
 8771                ranges_for_buffer.push(range.clone());
 8772
 8773                while let Some(next_location) = locations.peek() {
 8774                    if next_location.buffer == location.buffer {
 8775                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
 8776                        locations.next();
 8777                    } else {
 8778                        break;
 8779                    }
 8780                }
 8781
 8782                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
 8783                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
 8784                    location.buffer.clone(),
 8785                    ranges_for_buffer,
 8786                    DEFAULT_MULTIBUFFER_CONTEXT,
 8787                    cx,
 8788                ))
 8789            }
 8790
 8791            multibuffer.with_title(title)
 8792        });
 8793
 8794        let editor = cx.new_view(|cx| {
 8795            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
 8796        });
 8797        editor.update(cx, |editor, cx| {
 8798            editor.highlight_background::<Self>(
 8799                &ranges_to_highlight,
 8800                |theme| theme.editor_highlighted_line_background,
 8801                cx,
 8802            );
 8803        });
 8804
 8805        let item = Box::new(editor);
 8806        let item_id = item.item_id();
 8807
 8808        if split {
 8809            workspace.split_item(SplitDirection::Right, item.clone(), cx);
 8810        } else {
 8811            let destination_index = workspace.active_pane().update(cx, |pane, cx| {
 8812                if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
 8813                    pane.close_current_preview_item(cx)
 8814                } else {
 8815                    None
 8816                }
 8817            });
 8818            workspace.add_item_to_active_pane(item.clone(), destination_index, cx);
 8819        }
 8820        workspace.active_pane().update(cx, |pane, cx| {
 8821            pane.set_preview_item_id(Some(item_id), cx);
 8822        });
 8823    }
 8824
 8825    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 8826        use language::ToOffset as _;
 8827
 8828        let project = self.project.clone()?;
 8829        let selection = self.selections.newest_anchor().clone();
 8830        let (cursor_buffer, cursor_buffer_position) = self
 8831            .buffer
 8832            .read(cx)
 8833            .text_anchor_for_position(selection.head(), cx)?;
 8834        let (tail_buffer, cursor_buffer_position_end) = self
 8835            .buffer
 8836            .read(cx)
 8837            .text_anchor_for_position(selection.tail(), cx)?;
 8838        if tail_buffer != cursor_buffer {
 8839            return None;
 8840        }
 8841
 8842        let snapshot = cursor_buffer.read(cx).snapshot();
 8843        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
 8844        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
 8845        let prepare_rename = project.update(cx, |project, cx| {
 8846            project.prepare_rename(cursor_buffer.clone(), cursor_buffer_offset, cx)
 8847        });
 8848        drop(snapshot);
 8849
 8850        Some(cx.spawn(|this, mut cx| async move {
 8851            let rename_range = if let Some(range) = prepare_rename.await? {
 8852                Some(range)
 8853            } else {
 8854                this.update(&mut cx, |this, cx| {
 8855                    let buffer = this.buffer.read(cx).snapshot(cx);
 8856                    let mut buffer_highlights = this
 8857                        .document_highlights_for_position(selection.head(), &buffer)
 8858                        .filter(|highlight| {
 8859                            highlight.start.excerpt_id == selection.head().excerpt_id
 8860                                && highlight.end.excerpt_id == selection.head().excerpt_id
 8861                        });
 8862                    buffer_highlights
 8863                        .next()
 8864                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
 8865                })?
 8866            };
 8867            if let Some(rename_range) = rename_range {
 8868                this.update(&mut cx, |this, cx| {
 8869                    let snapshot = cursor_buffer.read(cx).snapshot();
 8870                    let rename_buffer_range = rename_range.to_offset(&snapshot);
 8871                    let cursor_offset_in_rename_range =
 8872                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
 8873                    let cursor_offset_in_rename_range_end =
 8874                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
 8875
 8876                    this.take_rename(false, cx);
 8877                    let buffer = this.buffer.read(cx).read(cx);
 8878                    let cursor_offset = selection.head().to_offset(&buffer);
 8879                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
 8880                    let rename_end = rename_start + rename_buffer_range.len();
 8881                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
 8882                    let mut old_highlight_id = None;
 8883                    let old_name: Arc<str> = buffer
 8884                        .chunks(rename_start..rename_end, true)
 8885                        .map(|chunk| {
 8886                            if old_highlight_id.is_none() {
 8887                                old_highlight_id = chunk.syntax_highlight_id;
 8888                            }
 8889                            chunk.text
 8890                        })
 8891                        .collect::<String>()
 8892                        .into();
 8893
 8894                    drop(buffer);
 8895
 8896                    // Position the selection in the rename editor so that it matches the current selection.
 8897                    this.show_local_selections = false;
 8898                    let rename_editor = cx.new_view(|cx| {
 8899                        let mut editor = Editor::single_line(cx);
 8900                        editor.buffer.update(cx, |buffer, cx| {
 8901                            buffer.edit([(0..0, old_name.clone())], None, cx)
 8902                        });
 8903                        let rename_selection_range = match cursor_offset_in_rename_range
 8904                            .cmp(&cursor_offset_in_rename_range_end)
 8905                        {
 8906                            Ordering::Equal => {
 8907                                editor.select_all(&SelectAll, cx);
 8908                                return editor;
 8909                            }
 8910                            Ordering::Less => {
 8911                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
 8912                            }
 8913                            Ordering::Greater => {
 8914                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
 8915                            }
 8916                        };
 8917                        if rename_selection_range.end > old_name.len() {
 8918                            editor.select_all(&SelectAll, cx);
 8919                        } else {
 8920                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8921                                s.select_ranges([rename_selection_range]);
 8922                            });
 8923                        }
 8924                        editor
 8925                    });
 8926
 8927                    let write_highlights =
 8928                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
 8929                    let read_highlights =
 8930                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
 8931                    let ranges = write_highlights
 8932                        .iter()
 8933                        .flat_map(|(_, ranges)| ranges.iter())
 8934                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
 8935                        .cloned()
 8936                        .collect();
 8937
 8938                    this.highlight_text::<Rename>(
 8939                        ranges,
 8940                        HighlightStyle {
 8941                            fade_out: Some(0.6),
 8942                            ..Default::default()
 8943                        },
 8944                        cx,
 8945                    );
 8946                    let rename_focus_handle = rename_editor.focus_handle(cx);
 8947                    cx.focus(&rename_focus_handle);
 8948                    let block_id = this.insert_blocks(
 8949                        [BlockProperties {
 8950                            style: BlockStyle::Flex,
 8951                            position: range.start,
 8952                            height: 1,
 8953                            render: Box::new({
 8954                                let rename_editor = rename_editor.clone();
 8955                                move |cx: &mut BlockContext| {
 8956                                    let mut text_style = cx.editor_style.text.clone();
 8957                                    if let Some(highlight_style) = old_highlight_id
 8958                                        .and_then(|h| h.style(&cx.editor_style.syntax))
 8959                                    {
 8960                                        text_style = text_style.highlight(highlight_style);
 8961                                    }
 8962                                    div()
 8963                                        .pl(cx.anchor_x)
 8964                                        .child(EditorElement::new(
 8965                                            &rename_editor,
 8966                                            EditorStyle {
 8967                                                background: cx.theme().system().transparent,
 8968                                                local_player: cx.editor_style.local_player,
 8969                                                text: text_style,
 8970                                                scrollbar_width: cx.editor_style.scrollbar_width,
 8971                                                syntax: cx.editor_style.syntax.clone(),
 8972                                                status: cx.editor_style.status.clone(),
 8973                                                inlay_hints_style: HighlightStyle {
 8974                                                    color: Some(cx.theme().status().hint),
 8975                                                    font_weight: Some(FontWeight::BOLD),
 8976                                                    ..HighlightStyle::default()
 8977                                                },
 8978                                                suggestions_style: HighlightStyle {
 8979                                                    color: Some(cx.theme().status().predictive),
 8980                                                    ..HighlightStyle::default()
 8981                                                },
 8982                                            },
 8983                                        ))
 8984                                        .into_any_element()
 8985                                }
 8986                            }),
 8987                            disposition: BlockDisposition::Below,
 8988                        }],
 8989                        Some(Autoscroll::fit()),
 8990                        cx,
 8991                    )[0];
 8992                    this.pending_rename = Some(RenameState {
 8993                        range,
 8994                        old_name,
 8995                        editor: rename_editor,
 8996                        block_id,
 8997                    });
 8998                })?;
 8999            }
 9000
 9001            Ok(())
 9002        }))
 9003    }
 9004
 9005    pub fn confirm_rename(
 9006        &mut self,
 9007        _: &ConfirmRename,
 9008        cx: &mut ViewContext<Self>,
 9009    ) -> Option<Task<Result<()>>> {
 9010        let rename = self.take_rename(false, cx)?;
 9011        let workspace = self.workspace()?;
 9012        let (start_buffer, start) = self
 9013            .buffer
 9014            .read(cx)
 9015            .text_anchor_for_position(rename.range.start, cx)?;
 9016        let (end_buffer, end) = self
 9017            .buffer
 9018            .read(cx)
 9019            .text_anchor_for_position(rename.range.end, cx)?;
 9020        if start_buffer != end_buffer {
 9021            return None;
 9022        }
 9023
 9024        let buffer = start_buffer;
 9025        let range = start..end;
 9026        let old_name = rename.old_name;
 9027        let new_name = rename.editor.read(cx).text(cx);
 9028
 9029        let rename = workspace
 9030            .read(cx)
 9031            .project()
 9032            .clone()
 9033            .update(cx, |project, cx| {
 9034                project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
 9035            });
 9036        let workspace = workspace.downgrade();
 9037
 9038        Some(cx.spawn(|editor, mut cx| async move {
 9039            let project_transaction = rename.await?;
 9040            Self::open_project_transaction(
 9041                &editor,
 9042                workspace,
 9043                project_transaction,
 9044                format!("Rename: {}{}", old_name, new_name),
 9045                cx.clone(),
 9046            )
 9047            .await?;
 9048
 9049            editor.update(&mut cx, |editor, cx| {
 9050                editor.refresh_document_highlights(cx);
 9051            })?;
 9052            Ok(())
 9053        }))
 9054    }
 9055
 9056    fn take_rename(
 9057        &mut self,
 9058        moving_cursor: bool,
 9059        cx: &mut ViewContext<Self>,
 9060    ) -> Option<RenameState> {
 9061        let rename = self.pending_rename.take()?;
 9062        if rename.editor.focus_handle(cx).is_focused(cx) {
 9063            cx.focus(&self.focus_handle);
 9064        }
 9065
 9066        self.remove_blocks(
 9067            [rename.block_id].into_iter().collect(),
 9068            Some(Autoscroll::fit()),
 9069            cx,
 9070        );
 9071        self.clear_highlights::<Rename>(cx);
 9072        self.show_local_selections = true;
 9073
 9074        if moving_cursor {
 9075            let rename_editor = rename.editor.read(cx);
 9076            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
 9077
 9078            // Update the selection to match the position of the selection inside
 9079            // the rename editor.
 9080            let snapshot = self.buffer.read(cx).read(cx);
 9081            let rename_range = rename.range.to_offset(&snapshot);
 9082            let cursor_in_editor = snapshot
 9083                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
 9084                .min(rename_range.end);
 9085            drop(snapshot);
 9086
 9087            self.change_selections(None, cx, |s| {
 9088                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
 9089            });
 9090        } else {
 9091            self.refresh_document_highlights(cx);
 9092        }
 9093
 9094        Some(rename)
 9095    }
 9096
 9097    pub fn pending_rename(&self) -> Option<&RenameState> {
 9098        self.pending_rename.as_ref()
 9099    }
 9100
 9101    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 9102        let project = match &self.project {
 9103            Some(project) => project.clone(),
 9104            None => return None,
 9105        };
 9106
 9107        Some(self.perform_format(project, FormatTrigger::Manual, cx))
 9108    }
 9109
 9110    fn perform_format(
 9111        &mut self,
 9112        project: Model<Project>,
 9113        trigger: FormatTrigger,
 9114        cx: &mut ViewContext<Self>,
 9115    ) -> Task<Result<()>> {
 9116        let buffer = self.buffer().clone();
 9117        let mut buffers = buffer.read(cx).all_buffers();
 9118        if trigger == FormatTrigger::Save {
 9119            buffers.retain(|buffer| buffer.read(cx).is_dirty());
 9120        }
 9121
 9122        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
 9123        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
 9124
 9125        cx.spawn(|_, mut cx| async move {
 9126            let transaction = futures::select_biased! {
 9127                () = timeout => {
 9128                    log::warn!("timed out waiting for formatting");
 9129                    None
 9130                }
 9131                transaction = format.log_err().fuse() => transaction,
 9132            };
 9133
 9134            buffer
 9135                .update(&mut cx, |buffer, cx| {
 9136                    if let Some(transaction) = transaction {
 9137                        if !buffer.is_singleton() {
 9138                            buffer.push_transaction(&transaction.0, cx);
 9139                        }
 9140                    }
 9141
 9142                    cx.notify();
 9143                })
 9144                .ok();
 9145
 9146            Ok(())
 9147        })
 9148    }
 9149
 9150    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
 9151        if let Some(project) = self.project.clone() {
 9152            self.buffer.update(cx, |multi_buffer, cx| {
 9153                project.update(cx, |project, cx| {
 9154                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
 9155                });
 9156            })
 9157        }
 9158    }
 9159
 9160    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
 9161        cx.show_character_palette();
 9162    }
 9163
 9164    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
 9165        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
 9166            let buffer = self.buffer.read(cx).snapshot(cx);
 9167            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
 9168            let is_valid = buffer
 9169                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
 9170                .any(|entry| {
 9171                    entry.diagnostic.is_primary
 9172                        && !entry.range.is_empty()
 9173                        && entry.range.start == primary_range_start
 9174                        && entry.diagnostic.message == active_diagnostics.primary_message
 9175                });
 9176
 9177            if is_valid != active_diagnostics.is_valid {
 9178                active_diagnostics.is_valid = is_valid;
 9179                let mut new_styles = HashMap::default();
 9180                for (block_id, diagnostic) in &active_diagnostics.blocks {
 9181                    new_styles.insert(
 9182                        *block_id,
 9183                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
 9184                    );
 9185                }
 9186                self.display_map
 9187                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
 9188            }
 9189        }
 9190    }
 9191
 9192    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
 9193        self.dismiss_diagnostics(cx);
 9194        let snapshot = self.snapshot(cx);
 9195        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
 9196            let buffer = self.buffer.read(cx).snapshot(cx);
 9197
 9198            let mut primary_range = None;
 9199            let mut primary_message = None;
 9200            let mut group_end = Point::zero();
 9201            let diagnostic_group = buffer
 9202                .diagnostic_group::<MultiBufferPoint>(group_id)
 9203                .filter_map(|entry| {
 9204                    if snapshot.is_line_folded(MultiBufferRow(entry.range.start.row))
 9205                        && (entry.range.start.row == entry.range.end.row
 9206                            || snapshot.is_line_folded(MultiBufferRow(entry.range.end.row)))
 9207                    {
 9208                        return None;
 9209                    }
 9210                    if entry.range.end > group_end {
 9211                        group_end = entry.range.end;
 9212                    }
 9213                    if entry.diagnostic.is_primary {
 9214                        primary_range = Some(entry.range.clone());
 9215                        primary_message = Some(entry.diagnostic.message.clone());
 9216                    }
 9217                    Some(entry)
 9218                })
 9219                .collect::<Vec<_>>();
 9220            let primary_range = primary_range?;
 9221            let primary_message = primary_message?;
 9222            let primary_range =
 9223                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
 9224
 9225            let blocks = display_map
 9226                .insert_blocks(
 9227                    diagnostic_group.iter().map(|entry| {
 9228                        let diagnostic = entry.diagnostic.clone();
 9229                        let message_height = diagnostic.message.matches('\n').count() as u8 + 1;
 9230                        BlockProperties {
 9231                            style: BlockStyle::Fixed,
 9232                            position: buffer.anchor_after(entry.range.start),
 9233                            height: message_height,
 9234                            render: diagnostic_block_renderer(diagnostic, true),
 9235                            disposition: BlockDisposition::Below,
 9236                        }
 9237                    }),
 9238                    cx,
 9239                )
 9240                .into_iter()
 9241                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
 9242                .collect();
 9243
 9244            Some(ActiveDiagnosticGroup {
 9245                primary_range,
 9246                primary_message,
 9247                group_id,
 9248                blocks,
 9249                is_valid: true,
 9250            })
 9251        });
 9252        self.active_diagnostics.is_some()
 9253    }
 9254
 9255    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
 9256        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
 9257            self.display_map.update(cx, |display_map, cx| {
 9258                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
 9259            });
 9260            cx.notify();
 9261        }
 9262    }
 9263
 9264    pub fn set_selections_from_remote(
 9265        &mut self,
 9266        selections: Vec<Selection<Anchor>>,
 9267        pending_selection: Option<Selection<Anchor>>,
 9268        cx: &mut ViewContext<Self>,
 9269    ) {
 9270        let old_cursor_position = self.selections.newest_anchor().head();
 9271        self.selections.change_with(cx, |s| {
 9272            s.select_anchors(selections);
 9273            if let Some(pending_selection) = pending_selection {
 9274                s.set_pending(pending_selection, SelectMode::Character);
 9275            } else {
 9276                s.clear_pending();
 9277            }
 9278        });
 9279        self.selections_did_change(false, &old_cursor_position, true, cx);
 9280    }
 9281
 9282    fn push_to_selection_history(&mut self) {
 9283        self.selection_history.push(SelectionHistoryEntry {
 9284            selections: self.selections.disjoint_anchors(),
 9285            select_next_state: self.select_next_state.clone(),
 9286            select_prev_state: self.select_prev_state.clone(),
 9287            add_selections_state: self.add_selections_state.clone(),
 9288        });
 9289    }
 9290
 9291    pub fn transact(
 9292        &mut self,
 9293        cx: &mut ViewContext<Self>,
 9294        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
 9295    ) -> Option<TransactionId> {
 9296        self.start_transaction_at(Instant::now(), cx);
 9297        update(self, cx);
 9298        self.end_transaction_at(Instant::now(), cx)
 9299    }
 9300
 9301    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
 9302        self.end_selection(cx);
 9303        if let Some(tx_id) = self
 9304            .buffer
 9305            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
 9306        {
 9307            self.selection_history
 9308                .insert_transaction(tx_id, self.selections.disjoint_anchors());
 9309            cx.emit(EditorEvent::TransactionBegun {
 9310                transaction_id: tx_id,
 9311            })
 9312        }
 9313    }
 9314
 9315    fn end_transaction_at(
 9316        &mut self,
 9317        now: Instant,
 9318        cx: &mut ViewContext<Self>,
 9319    ) -> Option<TransactionId> {
 9320        if let Some(tx_id) = self
 9321            .buffer
 9322            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 9323        {
 9324            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
 9325                *end_selections = Some(self.selections.disjoint_anchors());
 9326            } else {
 9327                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
 9328            }
 9329
 9330            cx.emit(EditorEvent::Edited);
 9331            Some(tx_id)
 9332        } else {
 9333            None
 9334        }
 9335    }
 9336
 9337    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
 9338        let mut fold_ranges = Vec::new();
 9339
 9340        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9341
 9342        let selections = self.selections.all_adjusted(cx);
 9343        for selection in selections {
 9344            let range = selection.range().sorted();
 9345            let buffer_start_row = range.start.row;
 9346
 9347            for row in (0..=range.end.row).rev() {
 9348                if let Some((foldable_range, fold_text)) =
 9349                    display_map.foldable_range(MultiBufferRow(row))
 9350                {
 9351                    if foldable_range.end.row >= buffer_start_row {
 9352                        fold_ranges.push((foldable_range, fold_text));
 9353                        if row <= range.start.row {
 9354                            break;
 9355                        }
 9356                    }
 9357                }
 9358            }
 9359        }
 9360
 9361        self.fold_ranges(fold_ranges, true, cx);
 9362    }
 9363
 9364    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
 9365        let buffer_row = fold_at.buffer_row;
 9366        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9367
 9368        if let Some((fold_range, placeholder)) = display_map.foldable_range(buffer_row) {
 9369            let autoscroll = self
 9370                .selections
 9371                .all::<Point>(cx)
 9372                .iter()
 9373                .any(|selection| fold_range.overlaps(&selection.range()));
 9374
 9375            self.fold_ranges([(fold_range, placeholder)], autoscroll, cx);
 9376        }
 9377    }
 9378
 9379    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
 9380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9381        let buffer = &display_map.buffer_snapshot;
 9382        let selections = self.selections.all::<Point>(cx);
 9383        let ranges = selections
 9384            .iter()
 9385            .map(|s| {
 9386                let range = s.display_range(&display_map).sorted();
 9387                let mut start = range.start.to_point(&display_map);
 9388                let mut end = range.end.to_point(&display_map);
 9389                start.column = 0;
 9390                end.column = buffer.line_len(MultiBufferRow(end.row));
 9391                start..end
 9392            })
 9393            .collect::<Vec<_>>();
 9394
 9395        self.unfold_ranges(ranges, true, true, cx);
 9396    }
 9397
 9398    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
 9399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9400
 9401        let intersection_range = Point::new(unfold_at.buffer_row.0, 0)
 9402            ..Point::new(
 9403                unfold_at.buffer_row.0,
 9404                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
 9405            );
 9406
 9407        let autoscroll = self
 9408            .selections
 9409            .all::<Point>(cx)
 9410            .iter()
 9411            .any(|selection| selection.range().overlaps(&intersection_range));
 9412
 9413        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
 9414    }
 9415
 9416    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
 9417        let selections = self.selections.all::<Point>(cx);
 9418        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9419        let line_mode = self.selections.line_mode;
 9420        let ranges = selections.into_iter().map(|s| {
 9421            if line_mode {
 9422                let start = Point::new(s.start.row, 0);
 9423                let end = Point::new(
 9424                    s.end.row,
 9425                    display_map
 9426                        .buffer_snapshot
 9427                        .line_len(MultiBufferRow(s.end.row)),
 9428                );
 9429                (start..end, display_map.fold_placeholder.clone())
 9430            } else {
 9431                (s.start..s.end, display_map.fold_placeholder.clone())
 9432            }
 9433        });
 9434        self.fold_ranges(ranges, true, cx);
 9435    }
 9436
 9437    pub fn fold_ranges<T: ToOffset + Clone>(
 9438        &mut self,
 9439        ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>,
 9440        auto_scroll: bool,
 9441        cx: &mut ViewContext<Self>,
 9442    ) {
 9443        let mut fold_ranges = Vec::new();
 9444        let mut buffers_affected = HashMap::default();
 9445        let multi_buffer = self.buffer().read(cx);
 9446        for (fold_range, fold_text) in ranges {
 9447            if let Some((_, buffer, _)) =
 9448                multi_buffer.excerpt_containing(fold_range.start.clone(), cx)
 9449            {
 9450                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
 9451            };
 9452            fold_ranges.push((fold_range, fold_text));
 9453        }
 9454
 9455        let mut ranges = fold_ranges.into_iter().peekable();
 9456        if ranges.peek().is_some() {
 9457            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
 9458
 9459            if auto_scroll {
 9460                self.request_autoscroll(Autoscroll::fit(), cx);
 9461            }
 9462
 9463            for buffer in buffers_affected.into_values() {
 9464                self.sync_expanded_diff_hunks(buffer, cx);
 9465            }
 9466
 9467            cx.notify();
 9468
 9469            if let Some(active_diagnostics) = self.active_diagnostics.take() {
 9470                // Clear diagnostics block when folding a range that contains it.
 9471                let snapshot = self.snapshot(cx);
 9472                if snapshot.intersects_fold(active_diagnostics.primary_range.start) {
 9473                    drop(snapshot);
 9474                    self.active_diagnostics = Some(active_diagnostics);
 9475                    self.dismiss_diagnostics(cx);
 9476                } else {
 9477                    self.active_diagnostics = Some(active_diagnostics);
 9478                }
 9479            }
 9480
 9481            self.scrollbar_marker_state.dirty = true;
 9482        }
 9483    }
 9484
 9485    pub fn unfold_ranges<T: ToOffset + Clone>(
 9486        &mut self,
 9487        ranges: impl IntoIterator<Item = Range<T>>,
 9488        inclusive: bool,
 9489        auto_scroll: bool,
 9490        cx: &mut ViewContext<Self>,
 9491    ) {
 9492        let mut unfold_ranges = Vec::new();
 9493        let mut buffers_affected = HashMap::default();
 9494        let multi_buffer = self.buffer().read(cx);
 9495        for range in ranges {
 9496            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
 9497                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
 9498            };
 9499            unfold_ranges.push(range);
 9500        }
 9501
 9502        let mut ranges = unfold_ranges.into_iter().peekable();
 9503        if ranges.peek().is_some() {
 9504            self.display_map
 9505                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
 9506            if auto_scroll {
 9507                self.request_autoscroll(Autoscroll::fit(), cx);
 9508            }
 9509
 9510            for buffer in buffers_affected.into_values() {
 9511                self.sync_expanded_diff_hunks(buffer, cx);
 9512            }
 9513
 9514            cx.notify();
 9515            self.scrollbar_marker_state.dirty = true;
 9516            self.active_indent_guides_state.dirty = true;
 9517        }
 9518    }
 9519
 9520    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
 9521        if hovered != self.gutter_hovered {
 9522            self.gutter_hovered = hovered;
 9523            cx.notify();
 9524        }
 9525    }
 9526
 9527    pub fn insert_blocks(
 9528        &mut self,
 9529        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
 9530        autoscroll: Option<Autoscroll>,
 9531        cx: &mut ViewContext<Self>,
 9532    ) -> Vec<BlockId> {
 9533        let blocks = self
 9534            .display_map
 9535            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
 9536        if let Some(autoscroll) = autoscroll {
 9537            self.request_autoscroll(autoscroll, cx);
 9538        }
 9539        blocks
 9540    }
 9541
 9542    pub fn replace_blocks(
 9543        &mut self,
 9544        blocks: HashMap<BlockId, RenderBlock>,
 9545        autoscroll: Option<Autoscroll>,
 9546        cx: &mut ViewContext<Self>,
 9547    ) {
 9548        self.display_map
 9549            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
 9550        if let Some(autoscroll) = autoscroll {
 9551            self.request_autoscroll(autoscroll, cx);
 9552        }
 9553    }
 9554
 9555    pub fn remove_blocks(
 9556        &mut self,
 9557        block_ids: HashSet<BlockId>,
 9558        autoscroll: Option<Autoscroll>,
 9559        cx: &mut ViewContext<Self>,
 9560    ) {
 9561        self.display_map.update(cx, |display_map, cx| {
 9562            display_map.remove_blocks(block_ids, cx)
 9563        });
 9564        if let Some(autoscroll) = autoscroll {
 9565            self.request_autoscroll(autoscroll, cx);
 9566        }
 9567    }
 9568
 9569    pub fn insert_flaps(
 9570        &mut self,
 9571        flaps: impl IntoIterator<Item = Flap>,
 9572        cx: &mut ViewContext<Self>,
 9573    ) -> Vec<FlapId> {
 9574        self.display_map
 9575            .update(cx, |map, cx| map.insert_flaps(flaps, cx))
 9576    }
 9577
 9578    pub fn remove_flaps(
 9579        &mut self,
 9580        ids: impl IntoIterator<Item = FlapId>,
 9581        cx: &mut ViewContext<Self>,
 9582    ) {
 9583        self.display_map
 9584            .update(cx, |map, cx| map.remove_flaps(ids, cx));
 9585    }
 9586
 9587    pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow {
 9588        self.display_map
 9589            .update(cx, |map, cx| map.snapshot(cx))
 9590            .longest_row()
 9591    }
 9592
 9593    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
 9594        self.display_map
 9595            .update(cx, |map, cx| map.snapshot(cx))
 9596            .max_point()
 9597    }
 9598
 9599    pub fn text(&self, cx: &AppContext) -> String {
 9600        self.buffer.read(cx).read(cx).text()
 9601    }
 9602
 9603    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
 9604        let text = self.text(cx);
 9605        let text = text.trim();
 9606
 9607        if text.is_empty() {
 9608            return None;
 9609        }
 9610
 9611        Some(text.to_string())
 9612    }
 9613
 9614    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
 9615        self.transact(cx, |this, cx| {
 9616            this.buffer
 9617                .read(cx)
 9618                .as_singleton()
 9619                .expect("you can only call set_text on editors for singleton buffers")
 9620                .update(cx, |buffer, cx| buffer.set_text(text, cx));
 9621        });
 9622    }
 9623
 9624    pub fn display_text(&self, cx: &mut AppContext) -> String {
 9625        self.display_map
 9626            .update(cx, |map, cx| map.snapshot(cx))
 9627            .text()
 9628    }
 9629
 9630    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
 9631        let mut wrap_guides = smallvec::smallvec![];
 9632
 9633        if self.show_wrap_guides == Some(false) {
 9634            return wrap_guides;
 9635        }
 9636
 9637        let settings = self.buffer.read(cx).settings_at(0, cx);
 9638        if settings.show_wrap_guides {
 9639            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
 9640                wrap_guides.push((soft_wrap as usize, true));
 9641            }
 9642            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
 9643        }
 9644
 9645        wrap_guides
 9646    }
 9647
 9648    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
 9649        let settings = self.buffer.read(cx).settings_at(0, cx);
 9650        let mode = self
 9651            .soft_wrap_mode_override
 9652            .unwrap_or_else(|| settings.soft_wrap);
 9653        match mode {
 9654            language_settings::SoftWrap::None => SoftWrap::None,
 9655            language_settings::SoftWrap::PreferLine => SoftWrap::PreferLine,
 9656            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
 9657            language_settings::SoftWrap::PreferredLineLength => {
 9658                SoftWrap::Column(settings.preferred_line_length)
 9659            }
 9660        }
 9661    }
 9662
 9663    pub fn set_soft_wrap_mode(
 9664        &mut self,
 9665        mode: language_settings::SoftWrap,
 9666        cx: &mut ViewContext<Self>,
 9667    ) {
 9668        self.soft_wrap_mode_override = Some(mode);
 9669        cx.notify();
 9670    }
 9671
 9672    pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
 9673        let rem_size = cx.rem_size();
 9674        self.display_map.update(cx, |map, cx| {
 9675            map.set_font(
 9676                style.text.font(),
 9677                style.text.font_size.to_pixels(rem_size),
 9678                cx,
 9679            )
 9680        });
 9681        self.style = Some(style);
 9682    }
 9683
 9684    pub fn style(&self) -> Option<&EditorStyle> {
 9685        self.style.as_ref()
 9686    }
 9687
 9688    // Called by the element. This method is not designed to be called outside of the editor
 9689    // element's layout code because it does not notify when rewrapping is computed synchronously.
 9690    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
 9691        self.display_map
 9692            .update(cx, |map, cx| map.set_wrap_width(width, cx))
 9693    }
 9694
 9695    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
 9696        if self.soft_wrap_mode_override.is_some() {
 9697            self.soft_wrap_mode_override.take();
 9698        } else {
 9699            let soft_wrap = match self.soft_wrap_mode(cx) {
 9700                SoftWrap::None | SoftWrap::PreferLine => language_settings::SoftWrap::EditorWidth,
 9701                SoftWrap::EditorWidth | SoftWrap::Column(_) => {
 9702                    language_settings::SoftWrap::PreferLine
 9703                }
 9704            };
 9705            self.soft_wrap_mode_override = Some(soft_wrap);
 9706        }
 9707        cx.notify();
 9708    }
 9709
 9710    pub fn toggle_indent_guides(&mut self, _: &ToggleIndentGuides, cx: &mut ViewContext<Self>) {
 9711        let currently_enabled = self.should_show_indent_guides(cx);
 9712        self.show_indent_guides = Some(!currently_enabled);
 9713        cx.notify();
 9714    }
 9715
 9716    fn should_show_indent_guides(&self, cx: &mut ViewContext<Self>) -> bool {
 9717        self.show_indent_guides.unwrap_or_else(|| {
 9718            self.buffer
 9719                .read(cx)
 9720                .settings_at(0, cx)
 9721                .indent_guides
 9722                .enabled
 9723        })
 9724    }
 9725
 9726    pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext<Self>) {
 9727        let mut editor_settings = EditorSettings::get_global(cx).clone();
 9728        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
 9729        EditorSettings::override_global(editor_settings, cx);
 9730    }
 9731
 9732    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
 9733        self.show_gutter = show_gutter;
 9734        cx.notify();
 9735    }
 9736
 9737    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut ViewContext<Self>) {
 9738        self.show_line_numbers = Some(show_line_numbers);
 9739        cx.notify();
 9740    }
 9741
 9742    pub fn set_show_git_diff_gutter(
 9743        &mut self,
 9744        show_git_diff_gutter: bool,
 9745        cx: &mut ViewContext<Self>,
 9746    ) {
 9747        self.show_git_diff_gutter = Some(show_git_diff_gutter);
 9748        cx.notify();
 9749    }
 9750
 9751    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut ViewContext<Self>) {
 9752        self.show_code_actions = Some(show_code_actions);
 9753        cx.notify();
 9754    }
 9755
 9756    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut ViewContext<Self>) {
 9757        self.show_wrap_guides = Some(show_wrap_guides);
 9758        cx.notify();
 9759    }
 9760
 9761    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut ViewContext<Self>) {
 9762        self.show_indent_guides = Some(show_indent_guides);
 9763        cx.notify();
 9764    }
 9765
 9766    pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
 9767        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 9768            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 9769                cx.reveal_path(&file.abs_path(cx));
 9770            }
 9771        }
 9772    }
 9773
 9774    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
 9775        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 9776            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 9777                if let Some(path) = file.abs_path(cx).to_str() {
 9778                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 9779                }
 9780            }
 9781        }
 9782    }
 9783
 9784    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
 9785        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 9786            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 9787                if let Some(path) = file.path().to_str() {
 9788                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 9789                }
 9790            }
 9791        }
 9792    }
 9793
 9794    pub fn toggle_git_blame(&mut self, _: &ToggleGitBlame, cx: &mut ViewContext<Self>) {
 9795        self.show_git_blame_gutter = !self.show_git_blame_gutter;
 9796
 9797        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
 9798            self.start_git_blame(true, cx);
 9799        }
 9800
 9801        cx.notify();
 9802    }
 9803
 9804    pub fn toggle_git_blame_inline(
 9805        &mut self,
 9806        _: &ToggleGitBlameInline,
 9807        cx: &mut ViewContext<Self>,
 9808    ) {
 9809        self.toggle_git_blame_inline_internal(true, cx);
 9810        cx.notify();
 9811    }
 9812
 9813    pub fn git_blame_inline_enabled(&self) -> bool {
 9814        self.git_blame_inline_enabled
 9815    }
 9816
 9817    fn start_git_blame(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
 9818        if let Some(project) = self.project.as_ref() {
 9819            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
 9820                return;
 9821            };
 9822
 9823            if buffer.read(cx).file().is_none() {
 9824                return;
 9825            }
 9826
 9827            let focused = self.focus_handle(cx).contains_focused(cx);
 9828
 9829            let project = project.clone();
 9830            let blame =
 9831                cx.new_model(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
 9832            self.blame_subscription = Some(cx.observe(&blame, |_, _, cx| cx.notify()));
 9833            self.blame = Some(blame);
 9834        }
 9835    }
 9836
 9837    fn toggle_git_blame_inline_internal(
 9838        &mut self,
 9839        user_triggered: bool,
 9840        cx: &mut ViewContext<Self>,
 9841    ) {
 9842        if self.git_blame_inline_enabled {
 9843            self.git_blame_inline_enabled = false;
 9844            self.show_git_blame_inline = false;
 9845            self.show_git_blame_inline_delay_task.take();
 9846        } else {
 9847            self.git_blame_inline_enabled = true;
 9848            self.start_git_blame_inline(user_triggered, cx);
 9849        }
 9850
 9851        cx.notify();
 9852    }
 9853
 9854    fn start_git_blame_inline(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
 9855        self.start_git_blame(user_triggered, cx);
 9856
 9857        if ProjectSettings::get_global(cx)
 9858            .git
 9859            .inline_blame_delay()
 9860            .is_some()
 9861        {
 9862            self.start_inline_blame_timer(cx);
 9863        } else {
 9864            self.show_git_blame_inline = true
 9865        }
 9866    }
 9867
 9868    pub fn blame(&self) -> Option<&Model<GitBlame>> {
 9869        self.blame.as_ref()
 9870    }
 9871
 9872    pub fn render_git_blame_gutter(&mut self, cx: &mut WindowContext) -> bool {
 9873        self.show_git_blame_gutter && self.has_blame_entries(cx)
 9874    }
 9875
 9876    pub fn render_git_blame_inline(&mut self, cx: &mut WindowContext) -> bool {
 9877        self.show_git_blame_inline
 9878            && self.focus_handle.is_focused(cx)
 9879            && !self.newest_selection_head_on_empty_line(cx)
 9880            && self.has_blame_entries(cx)
 9881    }
 9882
 9883    fn has_blame_entries(&self, cx: &mut WindowContext) -> bool {
 9884        self.blame()
 9885            .map_or(false, |blame| blame.read(cx).has_generated_entries())
 9886    }
 9887
 9888    fn newest_selection_head_on_empty_line(&mut self, cx: &mut WindowContext) -> bool {
 9889        let cursor_anchor = self.selections.newest_anchor().head();
 9890
 9891        let snapshot = self.buffer.read(cx).snapshot(cx);
 9892        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
 9893
 9894        snapshot.line_len(buffer_row) == 0
 9895    }
 9896
 9897    fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Result<url::Url> {
 9898        let (path, repo) = maybe!({
 9899            let project_handle = self.project.as_ref()?.clone();
 9900            let project = project_handle.read(cx);
 9901            let buffer = self.buffer().read(cx).as_singleton()?;
 9902            let path = buffer
 9903                .read(cx)
 9904                .file()?
 9905                .as_local()?
 9906                .path()
 9907                .to_str()?
 9908                .to_string();
 9909            let repo = project.get_repo(&buffer.read(cx).project_path(cx)?, cx)?;
 9910            Some((path, repo))
 9911        })
 9912        .ok_or_else(|| anyhow!("unable to open git repository"))?;
 9913
 9914        const REMOTE_NAME: &str = "origin";
 9915        let origin_url = repo
 9916            .lock()
 9917            .remote_url(REMOTE_NAME)
 9918            .ok_or_else(|| anyhow!("remote \"{REMOTE_NAME}\" not found"))?;
 9919        let sha = repo
 9920            .lock()
 9921            .head_sha()
 9922            .ok_or_else(|| anyhow!("failed to read HEAD SHA"))?;
 9923        let selections = self.selections.all::<Point>(cx);
 9924        let selection = selections.iter().peekable().next();
 9925
 9926        let (provider, remote) =
 9927            parse_git_remote_url(GitHostingProviderRegistry::default_global(cx), &origin_url)
 9928                .ok_or_else(|| anyhow!("failed to parse Git remote URL"))?;
 9929
 9930        Ok(provider.build_permalink(
 9931            remote,
 9932            BuildPermalinkParams {
 9933                sha: &sha,
 9934                path: &path,
 9935                selection: selection.map(|selection| {
 9936                    let range = selection.range();
 9937                    let start = range.start.row;
 9938                    let end = range.end.row;
 9939                    start..end
 9940                }),
 9941            },
 9942        ))
 9943    }
 9944
 9945    pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
 9946        let permalink = self.get_permalink_to_line(cx);
 9947
 9948        match permalink {
 9949            Ok(permalink) => {
 9950                cx.write_to_clipboard(ClipboardItem::new(permalink.to_string()));
 9951            }
 9952            Err(err) => {
 9953                let message = format!("Failed to copy permalink: {err}");
 9954
 9955                Err::<(), anyhow::Error>(err).log_err();
 9956
 9957                if let Some(workspace) = self.workspace() {
 9958                    workspace.update(cx, |workspace, cx| {
 9959                        struct CopyPermalinkToLine;
 9960
 9961                        workspace.show_toast(
 9962                            Toast::new(NotificationId::unique::<CopyPermalinkToLine>(), message),
 9963                            cx,
 9964                        )
 9965                    })
 9966                }
 9967            }
 9968        }
 9969    }
 9970
 9971    pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
 9972        let permalink = self.get_permalink_to_line(cx);
 9973
 9974        match permalink {
 9975            Ok(permalink) => {
 9976                cx.open_url(permalink.as_ref());
 9977            }
 9978            Err(err) => {
 9979                let message = format!("Failed to open permalink: {err}");
 9980
 9981                Err::<(), anyhow::Error>(err).log_err();
 9982
 9983                if let Some(workspace) = self.workspace() {
 9984                    workspace.update(cx, |workspace, cx| {
 9985                        struct OpenPermalinkToLine;
 9986
 9987                        workspace.show_toast(
 9988                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
 9989                            cx,
 9990                        )
 9991                    })
 9992                }
 9993            }
 9994        }
 9995    }
 9996
 9997    /// Adds or removes (on `None` color) a highlight for the rows corresponding to the anchor range given.
 9998    /// On matching anchor range, replaces the old highlight; does not clear the other existing highlights.
 9999    /// If multiple anchor ranges will produce highlights for the same row, the last range added will be used.
10000    pub fn highlight_rows<T: 'static>(
10001        &mut self,
10002        rows: RangeInclusive<Anchor>,
10003        color: Option<Hsla>,
10004        should_autoscroll: bool,
10005        cx: &mut ViewContext<Self>,
10006    ) {
10007        let snapshot = self.buffer().read(cx).snapshot(cx);
10008        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
10009        let existing_highlight_index = row_highlights.binary_search_by(|highlight| {
10010            highlight
10011                .range
10012                .start()
10013                .cmp(&rows.start(), &snapshot)
10014                .then(highlight.range.end().cmp(&rows.end(), &snapshot))
10015        });
10016        match (color, existing_highlight_index) {
10017            (Some(_), Ok(ix)) | (_, Err(ix)) => row_highlights.insert(
10018                ix,
10019                RowHighlight {
10020                    index: post_inc(&mut self.highlight_order),
10021                    range: rows,
10022                    should_autoscroll,
10023                    color,
10024                },
10025            ),
10026            (None, Ok(i)) => {
10027                row_highlights.remove(i);
10028            }
10029        }
10030    }
10031
10032    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
10033    pub fn clear_row_highlights<T: 'static>(&mut self) {
10034        self.highlighted_rows.remove(&TypeId::of::<T>());
10035    }
10036
10037    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
10038    pub fn highlighted_rows<T: 'static>(
10039        &self,
10040    ) -> Option<impl Iterator<Item = (&RangeInclusive<Anchor>, Option<&Hsla>)>> {
10041        Some(
10042            self.highlighted_rows
10043                .get(&TypeId::of::<T>())?
10044                .iter()
10045                .map(|highlight| (&highlight.range, highlight.color.as_ref())),
10046        )
10047    }
10048
10049    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
10050    /// Rerturns a map of display rows that are highlighted and their corresponding highlight color.
10051    /// Allows to ignore certain kinds of highlights.
10052    pub fn highlighted_display_rows(
10053        &mut self,
10054        cx: &mut WindowContext,
10055    ) -> BTreeMap<DisplayRow, Hsla> {
10056        let snapshot = self.snapshot(cx);
10057        let mut used_highlight_orders = HashMap::default();
10058        self.highlighted_rows
10059            .iter()
10060            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
10061            .fold(
10062                BTreeMap::<DisplayRow, Hsla>::new(),
10063                |mut unique_rows, highlight| {
10064                    let start_row = highlight.range.start().to_display_point(&snapshot).row();
10065                    let end_row = highlight.range.end().to_display_point(&snapshot).row();
10066                    for row in start_row.0..=end_row.0 {
10067                        let used_index =
10068                            used_highlight_orders.entry(row).or_insert(highlight.index);
10069                        if highlight.index >= *used_index {
10070                            *used_index = highlight.index;
10071                            match highlight.color {
10072                                Some(hsla) => unique_rows.insert(DisplayRow(row), hsla),
10073                                None => unique_rows.remove(&DisplayRow(row)),
10074                            };
10075                        }
10076                    }
10077                    unique_rows
10078                },
10079            )
10080    }
10081
10082    pub fn highlighted_display_row_for_autoscroll(
10083        &self,
10084        snapshot: &DisplaySnapshot,
10085    ) -> Option<DisplayRow> {
10086        self.highlighted_rows
10087            .values()
10088            .flat_map(|highlighted_rows| highlighted_rows.iter())
10089            .filter_map(|highlight| {
10090                if highlight.color.is_none() || !highlight.should_autoscroll {
10091                    return None;
10092                }
10093                Some(highlight.range.start().to_display_point(&snapshot).row())
10094            })
10095            .min()
10096    }
10097
10098    pub fn set_search_within_ranges(
10099        &mut self,
10100        ranges: &[Range<Anchor>],
10101        cx: &mut ViewContext<Self>,
10102    ) {
10103        self.highlight_background::<SearchWithinRange>(
10104            ranges,
10105            |colors| colors.editor_document_highlight_read_background,
10106            cx,
10107        )
10108    }
10109
10110    pub fn clear_search_within_ranges(&mut self, cx: &mut ViewContext<Self>) {
10111        self.clear_background_highlights::<SearchWithinRange>(cx);
10112    }
10113
10114    pub fn highlight_background<T: 'static>(
10115        &mut self,
10116        ranges: &[Range<Anchor>],
10117        color_fetcher: fn(&ThemeColors) -> Hsla,
10118        cx: &mut ViewContext<Self>,
10119    ) {
10120        let snapshot = self.snapshot(cx);
10121        // this is to try and catch a panic sooner
10122        for range in ranges {
10123            snapshot
10124                .buffer_snapshot
10125                .summary_for_anchor::<usize>(&range.start);
10126            snapshot
10127                .buffer_snapshot
10128                .summary_for_anchor::<usize>(&range.end);
10129        }
10130
10131        self.background_highlights
10132            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
10133        self.scrollbar_marker_state.dirty = true;
10134        cx.notify();
10135    }
10136
10137    pub fn clear_background_highlights<T: 'static>(
10138        &mut self,
10139        cx: &mut ViewContext<Self>,
10140    ) -> Option<BackgroundHighlight> {
10141        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
10142        if !text_highlights.1.is_empty() {
10143            self.scrollbar_marker_state.dirty = true;
10144            cx.notify();
10145        }
10146        Some(text_highlights)
10147    }
10148
10149    #[cfg(feature = "test-support")]
10150    pub fn all_text_background_highlights(
10151        &mut self,
10152        cx: &mut ViewContext<Self>,
10153    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
10154        let snapshot = self.snapshot(cx);
10155        let buffer = &snapshot.buffer_snapshot;
10156        let start = buffer.anchor_before(0);
10157        let end = buffer.anchor_after(buffer.len());
10158        let theme = cx.theme().colors();
10159        self.background_highlights_in_range(start..end, &snapshot, theme)
10160    }
10161
10162    fn document_highlights_for_position<'a>(
10163        &'a self,
10164        position: Anchor,
10165        buffer: &'a MultiBufferSnapshot,
10166    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
10167        let read_highlights = self
10168            .background_highlights
10169            .get(&TypeId::of::<DocumentHighlightRead>())
10170            .map(|h| &h.1);
10171        let write_highlights = self
10172            .background_highlights
10173            .get(&TypeId::of::<DocumentHighlightWrite>())
10174            .map(|h| &h.1);
10175        let left_position = position.bias_left(buffer);
10176        let right_position = position.bias_right(buffer);
10177        read_highlights
10178            .into_iter()
10179            .chain(write_highlights)
10180            .flat_map(move |ranges| {
10181                let start_ix = match ranges.binary_search_by(|probe| {
10182                    let cmp = probe.end.cmp(&left_position, buffer);
10183                    if cmp.is_ge() {
10184                        Ordering::Greater
10185                    } else {
10186                        Ordering::Less
10187                    }
10188                }) {
10189                    Ok(i) | Err(i) => i,
10190                };
10191
10192                ranges[start_ix..]
10193                    .iter()
10194                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
10195            })
10196    }
10197
10198    pub fn has_background_highlights<T: 'static>(&self) -> bool {
10199        self.background_highlights
10200            .get(&TypeId::of::<T>())
10201            .map_or(false, |(_, highlights)| !highlights.is_empty())
10202    }
10203
10204    pub fn background_highlights_in_range(
10205        &self,
10206        search_range: Range<Anchor>,
10207        display_snapshot: &DisplaySnapshot,
10208        theme: &ThemeColors,
10209    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
10210        let mut results = Vec::new();
10211        for (color_fetcher, ranges) in self.background_highlights.values() {
10212            let color = color_fetcher(theme);
10213            let start_ix = match ranges.binary_search_by(|probe| {
10214                let cmp = probe
10215                    .end
10216                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
10217                if cmp.is_gt() {
10218                    Ordering::Greater
10219                } else {
10220                    Ordering::Less
10221                }
10222            }) {
10223                Ok(i) | Err(i) => i,
10224            };
10225            for range in &ranges[start_ix..] {
10226                if range
10227                    .start
10228                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
10229                    .is_ge()
10230                {
10231                    break;
10232                }
10233
10234                let start = range.start.to_display_point(&display_snapshot);
10235                let end = range.end.to_display_point(&display_snapshot);
10236                results.push((start..end, color))
10237            }
10238        }
10239        results
10240    }
10241
10242    pub fn background_highlight_row_ranges<T: 'static>(
10243        &self,
10244        search_range: Range<Anchor>,
10245        display_snapshot: &DisplaySnapshot,
10246        count: usize,
10247    ) -> Vec<RangeInclusive<DisplayPoint>> {
10248        let mut results = Vec::new();
10249        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
10250            return vec![];
10251        };
10252
10253        let start_ix = match ranges.binary_search_by(|probe| {
10254            let cmp = probe
10255                .end
10256                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
10257            if cmp.is_gt() {
10258                Ordering::Greater
10259            } else {
10260                Ordering::Less
10261            }
10262        }) {
10263            Ok(i) | Err(i) => i,
10264        };
10265        let mut push_region = |start: Option<Point>, end: Option<Point>| {
10266            if let (Some(start_display), Some(end_display)) = (start, end) {
10267                results.push(
10268                    start_display.to_display_point(display_snapshot)
10269                        ..=end_display.to_display_point(display_snapshot),
10270                );
10271            }
10272        };
10273        let mut start_row: Option<Point> = None;
10274        let mut end_row: Option<Point> = None;
10275        if ranges.len() > count {
10276            return Vec::new();
10277        }
10278        for range in &ranges[start_ix..] {
10279            if range
10280                .start
10281                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
10282                .is_ge()
10283            {
10284                break;
10285            }
10286            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
10287            if let Some(current_row) = &end_row {
10288                if end.row == current_row.row {
10289                    continue;
10290                }
10291            }
10292            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
10293            if start_row.is_none() {
10294                assert_eq!(end_row, None);
10295                start_row = Some(start);
10296                end_row = Some(end);
10297                continue;
10298            }
10299            if let Some(current_end) = end_row.as_mut() {
10300                if start.row > current_end.row + 1 {
10301                    push_region(start_row, end_row);
10302                    start_row = Some(start);
10303                    end_row = Some(end);
10304                } else {
10305                    // Merge two hunks.
10306                    *current_end = end;
10307                }
10308            } else {
10309                unreachable!();
10310            }
10311        }
10312        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
10313        push_region(start_row, end_row);
10314        results
10315    }
10316
10317    /// Get the text ranges corresponding to the redaction query
10318    pub fn redacted_ranges(
10319        &self,
10320        search_range: Range<Anchor>,
10321        display_snapshot: &DisplaySnapshot,
10322        cx: &WindowContext,
10323    ) -> Vec<Range<DisplayPoint>> {
10324        display_snapshot
10325            .buffer_snapshot
10326            .redacted_ranges(search_range, |file| {
10327                if let Some(file) = file {
10328                    file.is_private()
10329                        && EditorSettings::get(Some(file.as_ref().into()), cx).redact_private_values
10330                } else {
10331                    false
10332                }
10333            })
10334            .map(|range| {
10335                range.start.to_display_point(display_snapshot)
10336                    ..range.end.to_display_point(display_snapshot)
10337            })
10338            .collect()
10339    }
10340
10341    pub fn highlight_text<T: 'static>(
10342        &mut self,
10343        ranges: Vec<Range<Anchor>>,
10344        style: HighlightStyle,
10345        cx: &mut ViewContext<Self>,
10346    ) {
10347        self.display_map.update(cx, |map, _| {
10348            map.highlight_text(TypeId::of::<T>(), ranges, style)
10349        });
10350        cx.notify();
10351    }
10352
10353    pub(crate) fn highlight_inlays<T: 'static>(
10354        &mut self,
10355        highlights: Vec<InlayHighlight>,
10356        style: HighlightStyle,
10357        cx: &mut ViewContext<Self>,
10358    ) {
10359        self.display_map.update(cx, |map, _| {
10360            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
10361        });
10362        cx.notify();
10363    }
10364
10365    pub fn text_highlights<'a, T: 'static>(
10366        &'a self,
10367        cx: &'a AppContext,
10368    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
10369        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
10370    }
10371
10372    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
10373        let cleared = self
10374            .display_map
10375            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
10376        if cleared {
10377            cx.notify();
10378        }
10379    }
10380
10381    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
10382        (self.read_only(cx) || self.blink_manager.read(cx).visible())
10383            && self.focus_handle.is_focused(cx)
10384    }
10385
10386    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
10387        cx.notify();
10388    }
10389
10390    fn on_buffer_event(
10391        &mut self,
10392        multibuffer: Model<MultiBuffer>,
10393        event: &multi_buffer::Event,
10394        cx: &mut ViewContext<Self>,
10395    ) {
10396        match event {
10397            multi_buffer::Event::Edited {
10398                singleton_buffer_edited,
10399            } => {
10400                self.scrollbar_marker_state.dirty = true;
10401                self.active_indent_guides_state.dirty = true;
10402                self.refresh_active_diagnostics(cx);
10403                self.refresh_code_actions(cx);
10404                if self.has_active_inline_completion(cx) {
10405                    self.update_visible_inline_completion(cx);
10406                }
10407                cx.emit(EditorEvent::BufferEdited);
10408                cx.emit(SearchEvent::MatchesInvalidated);
10409
10410                if *singleton_buffer_edited {
10411                    if let Some(project) = &self.project {
10412                        let project = project.read(cx);
10413                        let languages_affected = multibuffer
10414                            .read(cx)
10415                            .all_buffers()
10416                            .into_iter()
10417                            .filter_map(|buffer| {
10418                                let buffer = buffer.read(cx);
10419                                let language = buffer.language()?;
10420                                if project.is_local()
10421                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
10422                                {
10423                                    None
10424                                } else {
10425                                    Some(language)
10426                                }
10427                            })
10428                            .cloned()
10429                            .collect::<HashSet<_>>();
10430                        if !languages_affected.is_empty() {
10431                            self.refresh_inlay_hints(
10432                                InlayHintRefreshReason::BufferEdited(languages_affected),
10433                                cx,
10434                            );
10435                        }
10436                    }
10437                }
10438
10439                let Some(project) = &self.project else { return };
10440                let telemetry = project.read(cx).client().telemetry().clone();
10441                telemetry.log_edit_event("editor");
10442            }
10443            multi_buffer::Event::ExcerptsAdded {
10444                buffer,
10445                predecessor,
10446                excerpts,
10447            } => {
10448                self.tasks_update_task = Some(self.refresh_runnables(cx));
10449                cx.emit(EditorEvent::ExcerptsAdded {
10450                    buffer: buffer.clone(),
10451                    predecessor: *predecessor,
10452                    excerpts: excerpts.clone(),
10453                });
10454                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
10455            }
10456            multi_buffer::Event::ExcerptsRemoved { ids } => {
10457                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
10458                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
10459            }
10460            multi_buffer::Event::Reparsed => {
10461                self.tasks_update_task = Some(self.refresh_runnables(cx));
10462
10463                cx.emit(EditorEvent::Reparsed);
10464            }
10465            multi_buffer::Event::LanguageChanged => {
10466                cx.emit(EditorEvent::Reparsed);
10467                cx.notify();
10468            }
10469            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
10470            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
10471            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
10472                cx.emit(EditorEvent::TitleChanged)
10473            }
10474            multi_buffer::Event::DiffBaseChanged => {
10475                self.scrollbar_marker_state.dirty = true;
10476                cx.emit(EditorEvent::DiffBaseChanged);
10477                cx.notify();
10478            }
10479            multi_buffer::Event::DiffUpdated { buffer } => {
10480                self.sync_expanded_diff_hunks(buffer.clone(), cx);
10481                cx.notify();
10482            }
10483            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
10484            multi_buffer::Event::DiagnosticsUpdated => {
10485                self.refresh_active_diagnostics(cx);
10486                self.scrollbar_marker_state.dirty = true;
10487                cx.notify();
10488            }
10489            _ => {}
10490        };
10491    }
10492
10493    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
10494        cx.notify();
10495    }
10496
10497    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
10498        self.refresh_inline_completion(true, cx);
10499        self.refresh_inlay_hints(
10500            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
10501                self.selections.newest_anchor().head(),
10502                &self.buffer.read(cx).snapshot(cx),
10503                cx,
10504            )),
10505            cx,
10506        );
10507        let editor_settings = EditorSettings::get_global(cx);
10508        self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
10509        self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
10510        self.current_line_highlight = editor_settings.current_line_highlight;
10511
10512        if self.mode == EditorMode::Full {
10513            let inline_blame_enabled = ProjectSettings::get_global(cx).git.inline_blame_enabled();
10514            if self.git_blame_inline_enabled != inline_blame_enabled {
10515                self.toggle_git_blame_inline_internal(false, cx);
10516            }
10517        }
10518
10519        cx.notify();
10520    }
10521
10522    pub fn set_searchable(&mut self, searchable: bool) {
10523        self.searchable = searchable;
10524    }
10525
10526    pub fn searchable(&self) -> bool {
10527        self.searchable
10528    }
10529
10530    fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
10531        self.open_excerpts_common(true, cx)
10532    }
10533
10534    fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
10535        self.open_excerpts_common(false, cx)
10536    }
10537
10538    fn open_excerpts_common(&mut self, split: bool, cx: &mut ViewContext<Self>) {
10539        let buffer = self.buffer.read(cx);
10540        if buffer.is_singleton() {
10541            cx.propagate();
10542            return;
10543        }
10544
10545        let Some(workspace) = self.workspace() else {
10546            cx.propagate();
10547            return;
10548        };
10549
10550        let mut new_selections_by_buffer = HashMap::default();
10551        for selection in self.selections.all::<usize>(cx) {
10552            for (buffer, mut range, _) in
10553                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
10554            {
10555                if selection.reversed {
10556                    mem::swap(&mut range.start, &mut range.end);
10557                }
10558                new_selections_by_buffer
10559                    .entry(buffer)
10560                    .or_insert(Vec::new())
10561                    .push(range)
10562            }
10563        }
10564
10565        // We defer the pane interaction because we ourselves are a workspace item
10566        // and activating a new item causes the pane to call a method on us reentrantly,
10567        // which panics if we're on the stack.
10568        cx.window_context().defer(move |cx| {
10569            workspace.update(cx, |workspace, cx| {
10570                let pane = if split {
10571                    workspace.adjacent_pane(cx)
10572                } else {
10573                    workspace.active_pane().clone()
10574                };
10575
10576                for (buffer, ranges) in new_selections_by_buffer {
10577                    let editor = workspace.open_project_item::<Self>(pane.clone(), buffer, cx);
10578                    editor.update(cx, |editor, cx| {
10579                        editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
10580                            s.select_ranges(ranges);
10581                        });
10582                    });
10583                }
10584            })
10585        });
10586    }
10587
10588    fn jump(
10589        &mut self,
10590        path: ProjectPath,
10591        position: Point,
10592        anchor: language::Anchor,
10593        offset_from_top: u32,
10594        cx: &mut ViewContext<Self>,
10595    ) {
10596        let workspace = self.workspace();
10597        cx.spawn(|_, mut cx| async move {
10598            let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
10599            let editor = workspace.update(&mut cx, |workspace, cx| {
10600                // Reset the preview item id before opening the new item
10601                workspace.active_pane().update(cx, |pane, cx| {
10602                    pane.set_preview_item_id(None, cx);
10603                });
10604                workspace.open_path_preview(path, None, true, true, cx)
10605            })?;
10606            let editor = editor
10607                .await?
10608                .downcast::<Editor>()
10609                .ok_or_else(|| anyhow!("opened item was not an editor"))?
10610                .downgrade();
10611            editor.update(&mut cx, |editor, cx| {
10612                let buffer = editor
10613                    .buffer()
10614                    .read(cx)
10615                    .as_singleton()
10616                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
10617                let buffer = buffer.read(cx);
10618                let cursor = if buffer.can_resolve(&anchor) {
10619                    language::ToPoint::to_point(&anchor, buffer)
10620                } else {
10621                    buffer.clip_point(position, Bias::Left)
10622                };
10623
10624                let nav_history = editor.nav_history.take();
10625                editor.change_selections(
10626                    Some(Autoscroll::top_relative(offset_from_top as usize)),
10627                    cx,
10628                    |s| {
10629                        s.select_ranges([cursor..cursor]);
10630                    },
10631                );
10632                editor.nav_history = nav_history;
10633
10634                anyhow::Ok(())
10635            })??;
10636
10637            anyhow::Ok(())
10638        })
10639        .detach_and_log_err(cx);
10640    }
10641
10642    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
10643        let snapshot = self.buffer.read(cx).read(cx);
10644        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
10645        Some(
10646            ranges
10647                .iter()
10648                .map(move |range| {
10649                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
10650                })
10651                .collect(),
10652        )
10653    }
10654
10655    fn selection_replacement_ranges(
10656        &self,
10657        range: Range<OffsetUtf16>,
10658        cx: &AppContext,
10659    ) -> Vec<Range<OffsetUtf16>> {
10660        let selections = self.selections.all::<OffsetUtf16>(cx);
10661        let newest_selection = selections
10662            .iter()
10663            .max_by_key(|selection| selection.id)
10664            .unwrap();
10665        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
10666        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
10667        let snapshot = self.buffer.read(cx).read(cx);
10668        selections
10669            .into_iter()
10670            .map(|mut selection| {
10671                selection.start.0 =
10672                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
10673                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
10674                snapshot.clip_offset_utf16(selection.start, Bias::Left)
10675                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
10676            })
10677            .collect()
10678    }
10679
10680    fn report_editor_event(
10681        &self,
10682        operation: &'static str,
10683        file_extension: Option<String>,
10684        cx: &AppContext,
10685    ) {
10686        if cfg!(any(test, feature = "test-support")) {
10687            return;
10688        }
10689
10690        let Some(project) = &self.project else { return };
10691
10692        // If None, we are in a file without an extension
10693        let file = self
10694            .buffer
10695            .read(cx)
10696            .as_singleton()
10697            .and_then(|b| b.read(cx).file());
10698        let file_extension = file_extension.or(file
10699            .as_ref()
10700            .and_then(|file| Path::new(file.file_name(cx)).extension())
10701            .and_then(|e| e.to_str())
10702            .map(|a| a.to_string()));
10703
10704        let vim_mode = cx
10705            .global::<SettingsStore>()
10706            .raw_user_settings()
10707            .get("vim_mode")
10708            == Some(&serde_json::Value::Bool(true));
10709
10710        let copilot_enabled = all_language_settings(file, cx).inline_completions.provider
10711            == language::language_settings::InlineCompletionProvider::Copilot;
10712        let copilot_enabled_for_language = self
10713            .buffer
10714            .read(cx)
10715            .settings_at(0, cx)
10716            .show_inline_completions;
10717
10718        let telemetry = project.read(cx).client().telemetry().clone();
10719        telemetry.report_editor_event(
10720            file_extension,
10721            vim_mode,
10722            operation,
10723            copilot_enabled,
10724            copilot_enabled_for_language,
10725        )
10726    }
10727
10728    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
10729    /// with each line being an array of {text, highlight} objects.
10730    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
10731        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
10732            return;
10733        };
10734
10735        #[derive(Serialize)]
10736        struct Chunk<'a> {
10737            text: String,
10738            highlight: Option<&'a str>,
10739        }
10740
10741        let snapshot = buffer.read(cx).snapshot();
10742        let range = self
10743            .selected_text_range(cx)
10744            .and_then(|selected_range| {
10745                if selected_range.is_empty() {
10746                    None
10747                } else {
10748                    Some(selected_range)
10749                }
10750            })
10751            .unwrap_or_else(|| 0..snapshot.len());
10752
10753        let chunks = snapshot.chunks(range, true);
10754        let mut lines = Vec::new();
10755        let mut line: VecDeque<Chunk> = VecDeque::new();
10756
10757        let Some(style) = self.style.as_ref() else {
10758            return;
10759        };
10760
10761        for chunk in chunks {
10762            let highlight = chunk
10763                .syntax_highlight_id
10764                .and_then(|id| id.name(&style.syntax));
10765            let mut chunk_lines = chunk.text.split('\n').peekable();
10766            while let Some(text) = chunk_lines.next() {
10767                let mut merged_with_last_token = false;
10768                if let Some(last_token) = line.back_mut() {
10769                    if last_token.highlight == highlight {
10770                        last_token.text.push_str(text);
10771                        merged_with_last_token = true;
10772                    }
10773                }
10774
10775                if !merged_with_last_token {
10776                    line.push_back(Chunk {
10777                        text: text.into(),
10778                        highlight,
10779                    });
10780                }
10781
10782                if chunk_lines.peek().is_some() {
10783                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
10784                        line.pop_front();
10785                    }
10786                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
10787                        line.pop_back();
10788                    }
10789
10790                    lines.push(mem::take(&mut line));
10791                }
10792            }
10793        }
10794
10795        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
10796            return;
10797        };
10798        cx.write_to_clipboard(ClipboardItem::new(lines));
10799    }
10800
10801    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
10802        &self.inlay_hint_cache
10803    }
10804
10805    pub fn replay_insert_event(
10806        &mut self,
10807        text: &str,
10808        relative_utf16_range: Option<Range<isize>>,
10809        cx: &mut ViewContext<Self>,
10810    ) {
10811        if !self.input_enabled {
10812            cx.emit(EditorEvent::InputIgnored { text: text.into() });
10813            return;
10814        }
10815        if let Some(relative_utf16_range) = relative_utf16_range {
10816            let selections = self.selections.all::<OffsetUtf16>(cx);
10817            self.change_selections(None, cx, |s| {
10818                let new_ranges = selections.into_iter().map(|range| {
10819                    let start = OffsetUtf16(
10820                        range
10821                            .head()
10822                            .0
10823                            .saturating_add_signed(relative_utf16_range.start),
10824                    );
10825                    let end = OffsetUtf16(
10826                        range
10827                            .head()
10828                            .0
10829                            .saturating_add_signed(relative_utf16_range.end),
10830                    );
10831                    start..end
10832                });
10833                s.select_ranges(new_ranges);
10834            });
10835        }
10836
10837        self.handle_input(text, cx);
10838    }
10839
10840    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
10841        let Some(project) = self.project.as_ref() else {
10842            return false;
10843        };
10844        let project = project.read(cx);
10845
10846        let mut supports = false;
10847        self.buffer().read(cx).for_each_buffer(|buffer| {
10848            if !supports {
10849                supports = project
10850                    .language_servers_for_buffer(buffer.read(cx), cx)
10851                    .any(
10852                        |(_, server)| match server.capabilities().inlay_hint_provider {
10853                            Some(lsp::OneOf::Left(enabled)) => enabled,
10854                            Some(lsp::OneOf::Right(_)) => true,
10855                            None => false,
10856                        },
10857                    )
10858            }
10859        });
10860        supports
10861    }
10862
10863    pub fn focus(&self, cx: &mut WindowContext) {
10864        cx.focus(&self.focus_handle)
10865    }
10866
10867    pub fn is_focused(&self, cx: &WindowContext) -> bool {
10868        self.focus_handle.is_focused(cx)
10869    }
10870
10871    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
10872        cx.emit(EditorEvent::Focused);
10873        if let Some(rename) = self.pending_rename.as_ref() {
10874            let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone();
10875            cx.focus(&rename_editor_focus_handle);
10876        } else {
10877            if let Some(blame) = self.blame.as_ref() {
10878                blame.update(cx, GitBlame::focus)
10879            }
10880
10881            self.blink_manager.update(cx, BlinkManager::enable);
10882            self.show_cursor_names(cx);
10883            self.buffer.update(cx, |buffer, cx| {
10884                buffer.finalize_last_transaction(cx);
10885                if self.leader_peer_id.is_none() {
10886                    buffer.set_active_selections(
10887                        &self.selections.disjoint_anchors(),
10888                        self.selections.line_mode,
10889                        self.cursor_shape,
10890                        cx,
10891                    );
10892                }
10893            });
10894        }
10895    }
10896
10897    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
10898        self.blink_manager.update(cx, BlinkManager::disable);
10899        self.buffer
10900            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
10901
10902        if let Some(blame) = self.blame.as_ref() {
10903            blame.update(cx, GitBlame::blur)
10904        }
10905        self.hide_context_menu(cx);
10906        hide_hover(self, cx);
10907        cx.emit(EditorEvent::Blurred);
10908        cx.notify();
10909    }
10910
10911    pub fn register_action<A: Action>(
10912        &mut self,
10913        listener: impl Fn(&A, &mut WindowContext) + 'static,
10914    ) -> &mut Self {
10915        let listener = Arc::new(listener);
10916
10917        self.editor_actions.push(Box::new(move |cx| {
10918            let _view = cx.view().clone();
10919            let cx = cx.window_context();
10920            let listener = listener.clone();
10921            cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
10922                let action = action.downcast_ref().unwrap();
10923                if phase == DispatchPhase::Bubble {
10924                    listener(action, cx)
10925                }
10926            })
10927        }));
10928        self
10929    }
10930}
10931
10932fn hunks_for_selections(
10933    multi_buffer_snapshot: &MultiBufferSnapshot,
10934    selections: &[Selection<Anchor>],
10935) -> Vec<DiffHunk<MultiBufferRow>> {
10936    let mut hunks = Vec::with_capacity(selections.len());
10937    let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
10938        HashMap::default();
10939    let buffer_rows_for_selections = selections.iter().map(|selection| {
10940        let head = selection.head();
10941        let tail = selection.tail();
10942        let start = MultiBufferRow(tail.to_point(&multi_buffer_snapshot).row);
10943        let end = MultiBufferRow(head.to_point(&multi_buffer_snapshot).row);
10944        if start > end {
10945            end..start
10946        } else {
10947            start..end
10948        }
10949    });
10950
10951    for selected_multi_buffer_rows in buffer_rows_for_selections {
10952        let query_rows =
10953            selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
10954        for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
10955            // Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
10956            // when the caret is just above or just below the deleted hunk.
10957            let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
10958            let related_to_selection = if allow_adjacent {
10959                hunk.associated_range.overlaps(&query_rows)
10960                    || hunk.associated_range.start == query_rows.end
10961                    || hunk.associated_range.end == query_rows.start
10962            } else {
10963                // `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
10964                // `hunk.associated_range` is exclusive (e.g. [2..3] means 2nd row is selected)
10965                hunk.associated_range.overlaps(&selected_multi_buffer_rows)
10966                    || selected_multi_buffer_rows.end == hunk.associated_range.start
10967            };
10968            if related_to_selection {
10969                if !processed_buffer_rows
10970                    .entry(hunk.buffer_id)
10971                    .or_default()
10972                    .insert(hunk.buffer_range.start..hunk.buffer_range.end)
10973                {
10974                    continue;
10975                }
10976                hunks.push(hunk);
10977            }
10978        }
10979    }
10980
10981    hunks
10982}
10983
10984pub trait CollaborationHub {
10985    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
10986    fn user_participant_indices<'a>(
10987        &self,
10988        cx: &'a AppContext,
10989    ) -> &'a HashMap<u64, ParticipantIndex>;
10990    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
10991}
10992
10993impl CollaborationHub for Model<Project> {
10994    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
10995        self.read(cx).collaborators()
10996    }
10997
10998    fn user_participant_indices<'a>(
10999        &self,
11000        cx: &'a AppContext,
11001    ) -> &'a HashMap<u64, ParticipantIndex> {
11002        self.read(cx).user_store().read(cx).participant_indices()
11003    }
11004
11005    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
11006        let this = self.read(cx);
11007        let user_ids = this.collaborators().values().map(|c| c.user_id);
11008        this.user_store().read_with(cx, |user_store, cx| {
11009            user_store.participant_names(user_ids, cx)
11010        })
11011    }
11012}
11013
11014pub trait CompletionProvider {
11015    fn completions(
11016        &self,
11017        buffer: &Model<Buffer>,
11018        buffer_position: text::Anchor,
11019        cx: &mut ViewContext<Editor>,
11020    ) -> Task<Result<Vec<Completion>>>;
11021
11022    fn resolve_completions(
11023        &self,
11024        buffer: Model<Buffer>,
11025        completion_indices: Vec<usize>,
11026        completions: Arc<RwLock<Box<[Completion]>>>,
11027        cx: &mut ViewContext<Editor>,
11028    ) -> Task<Result<bool>>;
11029
11030    fn apply_additional_edits_for_completion(
11031        &self,
11032        buffer: Model<Buffer>,
11033        completion: Completion,
11034        push_to_history: bool,
11035        cx: &mut ViewContext<Editor>,
11036    ) -> Task<Result<Option<language::Transaction>>>;
11037
11038    fn is_completion_trigger(
11039        &self,
11040        buffer: &Model<Buffer>,
11041        position: language::Anchor,
11042        text: &str,
11043        trigger_in_words: bool,
11044        cx: &mut ViewContext<Editor>,
11045    ) -> bool;
11046}
11047
11048impl CompletionProvider for Model<Project> {
11049    fn completions(
11050        &self,
11051        buffer: &Model<Buffer>,
11052        buffer_position: text::Anchor,
11053        cx: &mut ViewContext<Editor>,
11054    ) -> Task<Result<Vec<Completion>>> {
11055        self.update(cx, |project, cx| {
11056            project.completions(&buffer, buffer_position, cx)
11057        })
11058    }
11059
11060    fn resolve_completions(
11061        &self,
11062        buffer: Model<Buffer>,
11063        completion_indices: Vec<usize>,
11064        completions: Arc<RwLock<Box<[Completion]>>>,
11065        cx: &mut ViewContext<Editor>,
11066    ) -> Task<Result<bool>> {
11067        self.update(cx, |project, cx| {
11068            project.resolve_completions(buffer, completion_indices, completions, cx)
11069        })
11070    }
11071
11072    fn apply_additional_edits_for_completion(
11073        &self,
11074        buffer: Model<Buffer>,
11075        completion: Completion,
11076        push_to_history: bool,
11077        cx: &mut ViewContext<Editor>,
11078    ) -> Task<Result<Option<language::Transaction>>> {
11079        self.update(cx, |project, cx| {
11080            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
11081        })
11082    }
11083
11084    fn is_completion_trigger(
11085        &self,
11086        buffer: &Model<Buffer>,
11087        position: language::Anchor,
11088        text: &str,
11089        trigger_in_words: bool,
11090        cx: &mut ViewContext<Editor>,
11091    ) -> bool {
11092        if !EditorSettings::get_global(cx).show_completions_on_input {
11093            return false;
11094        }
11095
11096        let mut chars = text.chars();
11097        let char = if let Some(char) = chars.next() {
11098            char
11099        } else {
11100            return false;
11101        };
11102        if chars.next().is_some() {
11103            return false;
11104        }
11105
11106        let buffer = buffer.read(cx);
11107        let scope = buffer.snapshot().language_scope_at(position);
11108        if trigger_in_words && char_kind(&scope, char) == CharKind::Word {
11109            return true;
11110        }
11111
11112        buffer
11113            .completion_triggers()
11114            .iter()
11115            .any(|string| string == text)
11116    }
11117}
11118
11119fn inlay_hint_settings(
11120    location: Anchor,
11121    snapshot: &MultiBufferSnapshot,
11122    cx: &mut ViewContext<'_, Editor>,
11123) -> InlayHintSettings {
11124    let file = snapshot.file_at(location);
11125    let language = snapshot.language_at(location);
11126    let settings = all_language_settings(file, cx);
11127    settings
11128        .language(language.map(|l| l.name()).as_deref())
11129        .inlay_hints
11130}
11131
11132fn consume_contiguous_rows(
11133    contiguous_row_selections: &mut Vec<Selection<Point>>,
11134    selection: &Selection<Point>,
11135    display_map: &DisplaySnapshot,
11136    selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
11137) -> (MultiBufferRow, MultiBufferRow) {
11138    contiguous_row_selections.push(selection.clone());
11139    let start_row = MultiBufferRow(selection.start.row);
11140    let mut end_row = ending_row(selection, display_map);
11141
11142    while let Some(next_selection) = selections.peek() {
11143        if next_selection.start.row <= end_row.0 {
11144            end_row = ending_row(next_selection, display_map);
11145            contiguous_row_selections.push(selections.next().unwrap().clone());
11146        } else {
11147            break;
11148        }
11149    }
11150    (start_row, end_row)
11151}
11152
11153fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
11154    if next_selection.end.column > 0 || next_selection.is_empty() {
11155        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
11156    } else {
11157        MultiBufferRow(next_selection.end.row)
11158    }
11159}
11160
11161impl EditorSnapshot {
11162    pub fn remote_selections_in_range<'a>(
11163        &'a self,
11164        range: &'a Range<Anchor>,
11165        collaboration_hub: &dyn CollaborationHub,
11166        cx: &'a AppContext,
11167    ) -> impl 'a + Iterator<Item = RemoteSelection> {
11168        let participant_names = collaboration_hub.user_names(cx);
11169        let participant_indices = collaboration_hub.user_participant_indices(cx);
11170        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
11171        let collaborators_by_replica_id = collaborators_by_peer_id
11172            .iter()
11173            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
11174            .collect::<HashMap<_, _>>();
11175        self.buffer_snapshot
11176            .remote_selections_in_range(range)
11177            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
11178                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
11179                let participant_index = participant_indices.get(&collaborator.user_id).copied();
11180                let user_name = participant_names.get(&collaborator.user_id).cloned();
11181                Some(RemoteSelection {
11182                    replica_id,
11183                    selection,
11184                    cursor_shape,
11185                    line_mode,
11186                    participant_index,
11187                    peer_id: collaborator.peer_id,
11188                    user_name,
11189                })
11190            })
11191    }
11192
11193    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
11194        self.display_snapshot.buffer_snapshot.language_at(position)
11195    }
11196
11197    pub fn is_focused(&self) -> bool {
11198        self.is_focused
11199    }
11200
11201    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
11202        self.placeholder_text.as_ref()
11203    }
11204
11205    pub fn scroll_position(&self) -> gpui::Point<f32> {
11206        self.scroll_anchor.scroll_position(&self.display_snapshot)
11207    }
11208
11209    pub fn gutter_dimensions(
11210        &self,
11211        font_id: FontId,
11212        font_size: Pixels,
11213        em_width: Pixels,
11214        max_line_number_width: Pixels,
11215        cx: &AppContext,
11216    ) -> GutterDimensions {
11217        if !self.show_gutter {
11218            return GutterDimensions::default();
11219        }
11220        let descent = cx.text_system().descent(font_id, font_size);
11221
11222        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
11223            matches!(
11224                ProjectSettings::get_global(cx).git.git_gutter,
11225                Some(GitGutterSetting::TrackedFiles)
11226            )
11227        });
11228        let gutter_settings = EditorSettings::get_global(cx).gutter;
11229        let show_line_numbers = self
11230            .show_line_numbers
11231            .unwrap_or_else(|| gutter_settings.line_numbers);
11232        let line_gutter_width = if show_line_numbers {
11233            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
11234            let min_width_for_number_on_gutter = em_width * 4.0;
11235            max_line_number_width.max(min_width_for_number_on_gutter)
11236        } else {
11237            0.0.into()
11238        };
11239
11240        let show_code_actions = self
11241            .show_code_actions
11242            .unwrap_or_else(|| gutter_settings.code_actions);
11243
11244        let git_blame_entries_width = self
11245            .render_git_blame_gutter
11246            .then_some(em_width * GIT_BLAME_GUTTER_WIDTH_CHARS);
11247
11248        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
11249        left_padding += if show_code_actions {
11250            em_width * 3.0
11251        } else if show_git_gutter && show_line_numbers {
11252            em_width * 2.0
11253        } else if show_git_gutter || show_line_numbers {
11254            em_width
11255        } else {
11256            px(0.)
11257        };
11258
11259        let right_padding = if gutter_settings.folds && show_line_numbers {
11260            em_width * 4.0
11261        } else if gutter_settings.folds {
11262            em_width * 3.0
11263        } else if show_line_numbers {
11264            em_width
11265        } else {
11266            px(0.)
11267        };
11268
11269        GutterDimensions {
11270            left_padding,
11271            right_padding,
11272            width: line_gutter_width + left_padding + right_padding,
11273            margin: -descent,
11274            git_blame_entries_width,
11275        }
11276    }
11277
11278    pub fn render_fold_toggle(
11279        &self,
11280        buffer_row: MultiBufferRow,
11281        row_contains_cursor: bool,
11282        editor: View<Editor>,
11283        cx: &mut WindowContext,
11284    ) -> Option<AnyElement> {
11285        let folded = self.is_line_folded(buffer_row);
11286
11287        if let Some(flap) = self
11288            .flap_snapshot
11289            .query_row(buffer_row, &self.buffer_snapshot)
11290        {
11291            let toggle_callback = Arc::new(move |folded, cx: &mut WindowContext| {
11292                if folded {
11293                    editor.update(cx, |editor, cx| {
11294                        editor.fold_at(&crate::FoldAt { buffer_row }, cx)
11295                    });
11296                } else {
11297                    editor.update(cx, |editor, cx| {
11298                        editor.unfold_at(&crate::UnfoldAt { buffer_row }, cx)
11299                    });
11300                }
11301            });
11302
11303            Some((flap.render_toggle)(
11304                buffer_row,
11305                folded,
11306                toggle_callback,
11307                cx,
11308            ))
11309        } else if folded
11310            || (self.starts_indent(buffer_row) && (row_contains_cursor || self.gutter_hovered))
11311        {
11312            Some(
11313                IconButton::new(
11314                    ("indent-fold-indicator", buffer_row.0),
11315                    ui::IconName::ChevronDown,
11316                )
11317                .on_click(cx.listener_for(&editor, move |this, _e, cx| {
11318                    if folded {
11319                        this.unfold_at(&UnfoldAt { buffer_row }, cx);
11320                    } else {
11321                        this.fold_at(&FoldAt { buffer_row }, cx);
11322                    }
11323                }))
11324                .icon_color(ui::Color::Muted)
11325                .icon_size(ui::IconSize::Small)
11326                .selected(folded)
11327                .selected_icon(ui::IconName::ChevronRight)
11328                .size(ui::ButtonSize::None)
11329                .into_any_element(),
11330            )
11331        } else {
11332            None
11333        }
11334    }
11335
11336    pub fn render_flap_trailer(
11337        &self,
11338        buffer_row: MultiBufferRow,
11339        cx: &mut WindowContext,
11340    ) -> Option<AnyElement> {
11341        let folded = self.is_line_folded(buffer_row);
11342        let flap = self
11343            .flap_snapshot
11344            .query_row(buffer_row, &self.buffer_snapshot)?;
11345        Some((flap.render_trailer)(buffer_row, folded, cx))
11346    }
11347}
11348
11349impl Deref for EditorSnapshot {
11350    type Target = DisplaySnapshot;
11351
11352    fn deref(&self) -> &Self::Target {
11353        &self.display_snapshot
11354    }
11355}
11356
11357#[derive(Clone, Debug, PartialEq, Eq)]
11358pub enum EditorEvent {
11359    InputIgnored {
11360        text: Arc<str>,
11361    },
11362    InputHandled {
11363        utf16_range_to_replace: Option<Range<isize>>,
11364        text: Arc<str>,
11365    },
11366    ExcerptsAdded {
11367        buffer: Model<Buffer>,
11368        predecessor: ExcerptId,
11369        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
11370    },
11371    ExcerptsRemoved {
11372        ids: Vec<ExcerptId>,
11373    },
11374    BufferEdited,
11375    Edited,
11376    Reparsed,
11377    Focused,
11378    Blurred,
11379    DirtyChanged,
11380    Saved,
11381    TitleChanged,
11382    DiffBaseChanged,
11383    SelectionsChanged {
11384        local: bool,
11385    },
11386    ScrollPositionChanged {
11387        local: bool,
11388        autoscroll: bool,
11389    },
11390    Closed,
11391    TransactionUndone {
11392        transaction_id: clock::Lamport,
11393    },
11394    TransactionBegun {
11395        transaction_id: clock::Lamport,
11396    },
11397}
11398
11399impl EventEmitter<EditorEvent> for Editor {}
11400
11401impl FocusableView for Editor {
11402    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
11403        self.focus_handle.clone()
11404    }
11405}
11406
11407impl Render for Editor {
11408    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
11409        let settings = ThemeSettings::get_global(cx);
11410
11411        let text_style = match self.mode {
11412            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
11413                color: cx.theme().colors().editor_foreground,
11414                font_family: settings.ui_font.family.clone(),
11415                font_features: settings.ui_font.features.clone(),
11416                font_size: rems(0.875).into(),
11417                font_weight: FontWeight::NORMAL,
11418                font_style: FontStyle::Normal,
11419                line_height: relative(settings.buffer_line_height.value()),
11420                background_color: None,
11421                underline: None,
11422                strikethrough: None,
11423                white_space: WhiteSpace::Normal,
11424            },
11425            EditorMode::Full => TextStyle {
11426                color: cx.theme().colors().editor_foreground,
11427                font_family: settings.buffer_font.family.clone(),
11428                font_features: settings.buffer_font.features.clone(),
11429                font_size: settings.buffer_font_size(cx).into(),
11430                font_weight: FontWeight::NORMAL,
11431                font_style: FontStyle::Normal,
11432                line_height: relative(settings.buffer_line_height.value()),
11433                background_color: None,
11434                underline: None,
11435                strikethrough: None,
11436                white_space: WhiteSpace::Normal,
11437            },
11438        };
11439
11440        let background = match self.mode {
11441            EditorMode::SingleLine => cx.theme().system().transparent,
11442            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
11443            EditorMode::Full => cx.theme().colors().editor_background,
11444        };
11445
11446        EditorElement::new(
11447            cx.view(),
11448            EditorStyle {
11449                background,
11450                local_player: cx.theme().players().local(),
11451                text: text_style,
11452                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
11453                syntax: cx.theme().syntax().clone(),
11454                status: cx.theme().status().clone(),
11455                inlay_hints_style: HighlightStyle {
11456                    color: Some(cx.theme().status().hint),
11457                    ..HighlightStyle::default()
11458                },
11459                suggestions_style: HighlightStyle {
11460                    color: Some(cx.theme().status().predictive),
11461                    ..HighlightStyle::default()
11462                },
11463            },
11464        )
11465    }
11466}
11467
11468impl ViewInputHandler for Editor {
11469    fn text_for_range(
11470        &mut self,
11471        range_utf16: Range<usize>,
11472        cx: &mut ViewContext<Self>,
11473    ) -> Option<String> {
11474        Some(
11475            self.buffer
11476                .read(cx)
11477                .read(cx)
11478                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
11479                .collect(),
11480        )
11481    }
11482
11483    fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
11484        // Prevent the IME menu from appearing when holding down an alphabetic key
11485        // while input is disabled.
11486        if !self.input_enabled {
11487            return None;
11488        }
11489
11490        let range = self.selections.newest::<OffsetUtf16>(cx).range();
11491        Some(range.start.0..range.end.0)
11492    }
11493
11494    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
11495        let snapshot = self.buffer.read(cx).read(cx);
11496        let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
11497        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
11498    }
11499
11500    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
11501        self.clear_highlights::<InputComposition>(cx);
11502        self.ime_transaction.take();
11503    }
11504
11505    fn replace_text_in_range(
11506        &mut self,
11507        range_utf16: Option<Range<usize>>,
11508        text: &str,
11509        cx: &mut ViewContext<Self>,
11510    ) {
11511        if !self.input_enabled {
11512            cx.emit(EditorEvent::InputIgnored { text: text.into() });
11513            return;
11514        }
11515
11516        self.transact(cx, |this, cx| {
11517            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
11518                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
11519                Some(this.selection_replacement_ranges(range_utf16, cx))
11520            } else {
11521                this.marked_text_ranges(cx)
11522            };
11523
11524            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
11525                let newest_selection_id = this.selections.newest_anchor().id;
11526                this.selections
11527                    .all::<OffsetUtf16>(cx)
11528                    .iter()
11529                    .zip(ranges_to_replace.iter())
11530                    .find_map(|(selection, range)| {
11531                        if selection.id == newest_selection_id {
11532                            Some(
11533                                (range.start.0 as isize - selection.head().0 as isize)
11534                                    ..(range.end.0 as isize - selection.head().0 as isize),
11535                            )
11536                        } else {
11537                            None
11538                        }
11539                    })
11540            });
11541
11542            cx.emit(EditorEvent::InputHandled {
11543                utf16_range_to_replace: range_to_replace,
11544                text: text.into(),
11545            });
11546
11547            if let Some(new_selected_ranges) = new_selected_ranges {
11548                this.change_selections(None, cx, |selections| {
11549                    selections.select_ranges(new_selected_ranges)
11550                });
11551                this.backspace(&Default::default(), cx);
11552            }
11553
11554            this.handle_input(text, cx);
11555        });
11556
11557        if let Some(transaction) = self.ime_transaction {
11558            self.buffer.update(cx, |buffer, cx| {
11559                buffer.group_until_transaction(transaction, cx);
11560            });
11561        }
11562
11563        self.unmark_text(cx);
11564    }
11565
11566    fn replace_and_mark_text_in_range(
11567        &mut self,
11568        range_utf16: Option<Range<usize>>,
11569        text: &str,
11570        new_selected_range_utf16: Option<Range<usize>>,
11571        cx: &mut ViewContext<Self>,
11572    ) {
11573        if !self.input_enabled {
11574            cx.emit(EditorEvent::InputIgnored { text: text.into() });
11575            return;
11576        }
11577
11578        let transaction = self.transact(cx, |this, cx| {
11579            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
11580                let snapshot = this.buffer.read(cx).read(cx);
11581                if let Some(relative_range_utf16) = range_utf16.as_ref() {
11582                    for marked_range in &mut marked_ranges {
11583                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
11584                        marked_range.start.0 += relative_range_utf16.start;
11585                        marked_range.start =
11586                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
11587                        marked_range.end =
11588                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
11589                    }
11590                }
11591                Some(marked_ranges)
11592            } else if let Some(range_utf16) = range_utf16 {
11593                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
11594                Some(this.selection_replacement_ranges(range_utf16, cx))
11595            } else {
11596                None
11597            };
11598
11599            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
11600                let newest_selection_id = this.selections.newest_anchor().id;
11601                this.selections
11602                    .all::<OffsetUtf16>(cx)
11603                    .iter()
11604                    .zip(ranges_to_replace.iter())
11605                    .find_map(|(selection, range)| {
11606                        if selection.id == newest_selection_id {
11607                            Some(
11608                                (range.start.0 as isize - selection.head().0 as isize)
11609                                    ..(range.end.0 as isize - selection.head().0 as isize),
11610                            )
11611                        } else {
11612                            None
11613                        }
11614                    })
11615            });
11616
11617            cx.emit(EditorEvent::InputHandled {
11618                utf16_range_to_replace: range_to_replace,
11619                text: text.into(),
11620            });
11621
11622            if let Some(ranges) = ranges_to_replace {
11623                this.change_selections(None, cx, |s| s.select_ranges(ranges));
11624            }
11625
11626            let marked_ranges = {
11627                let snapshot = this.buffer.read(cx).read(cx);
11628                this.selections
11629                    .disjoint_anchors()
11630                    .iter()
11631                    .map(|selection| {
11632                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
11633                    })
11634                    .collect::<Vec<_>>()
11635            };
11636
11637            if text.is_empty() {
11638                this.unmark_text(cx);
11639            } else {
11640                this.highlight_text::<InputComposition>(
11641                    marked_ranges.clone(),
11642                    HighlightStyle {
11643                        underline: Some(UnderlineStyle {
11644                            thickness: px(1.),
11645                            color: None,
11646                            wavy: false,
11647                        }),
11648                        ..Default::default()
11649                    },
11650                    cx,
11651                );
11652            }
11653
11654            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
11655            let use_autoclose = this.use_autoclose;
11656            this.set_use_autoclose(false);
11657            this.handle_input(text, cx);
11658            this.set_use_autoclose(use_autoclose);
11659
11660            if let Some(new_selected_range) = new_selected_range_utf16 {
11661                let snapshot = this.buffer.read(cx).read(cx);
11662                let new_selected_ranges = marked_ranges
11663                    .into_iter()
11664                    .map(|marked_range| {
11665                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
11666                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
11667                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
11668                        snapshot.clip_offset_utf16(new_start, Bias::Left)
11669                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
11670                    })
11671                    .collect::<Vec<_>>();
11672
11673                drop(snapshot);
11674                this.change_selections(None, cx, |selections| {
11675                    selections.select_ranges(new_selected_ranges)
11676                });
11677            }
11678        });
11679
11680        self.ime_transaction = self.ime_transaction.or(transaction);
11681        if let Some(transaction) = self.ime_transaction {
11682            self.buffer.update(cx, |buffer, cx| {
11683                buffer.group_until_transaction(transaction, cx);
11684            });
11685        }
11686
11687        if self.text_highlights::<InputComposition>(cx).is_none() {
11688            self.ime_transaction.take();
11689        }
11690    }
11691
11692    fn bounds_for_range(
11693        &mut self,
11694        range_utf16: Range<usize>,
11695        element_bounds: gpui::Bounds<Pixels>,
11696        cx: &mut ViewContext<Self>,
11697    ) -> Option<gpui::Bounds<Pixels>> {
11698        let text_layout_details = self.text_layout_details(cx);
11699        let style = &text_layout_details.editor_style;
11700        let font_id = cx.text_system().resolve_font(&style.text.font());
11701        let font_size = style.text.font_size.to_pixels(cx.rem_size());
11702        let line_height = style.text.line_height_in_pixels(cx.rem_size());
11703        let em_width = cx
11704            .text_system()
11705            .typographic_bounds(font_id, font_size, 'm')
11706            .unwrap()
11707            .size
11708            .width;
11709
11710        let snapshot = self.snapshot(cx);
11711        let scroll_position = snapshot.scroll_position();
11712        let scroll_left = scroll_position.x * em_width;
11713
11714        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
11715        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
11716            + self.gutter_dimensions.width;
11717        let y = line_height * (start.row().as_f32() - scroll_position.y);
11718
11719        Some(Bounds {
11720            origin: element_bounds.origin + point(x, y),
11721            size: size(em_width, line_height),
11722        })
11723    }
11724}
11725
11726trait SelectionExt {
11727    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
11728    fn spanned_rows(
11729        &self,
11730        include_end_if_at_line_start: bool,
11731        map: &DisplaySnapshot,
11732    ) -> Range<MultiBufferRow>;
11733}
11734
11735impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
11736    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
11737        let start = self
11738            .start
11739            .to_point(&map.buffer_snapshot)
11740            .to_display_point(map);
11741        let end = self
11742            .end
11743            .to_point(&map.buffer_snapshot)
11744            .to_display_point(map);
11745        if self.reversed {
11746            end..start
11747        } else {
11748            start..end
11749        }
11750    }
11751
11752    fn spanned_rows(
11753        &self,
11754        include_end_if_at_line_start: bool,
11755        map: &DisplaySnapshot,
11756    ) -> Range<MultiBufferRow> {
11757        let start = self.start.to_point(&map.buffer_snapshot);
11758        let mut end = self.end.to_point(&map.buffer_snapshot);
11759        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
11760            end.row -= 1;
11761        }
11762
11763        let buffer_start = map.prev_line_boundary(start).0;
11764        let buffer_end = map.next_line_boundary(end).0;
11765        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
11766    }
11767}
11768
11769impl<T: InvalidationRegion> InvalidationStack<T> {
11770    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
11771    where
11772        S: Clone + ToOffset,
11773    {
11774        while let Some(region) = self.last() {
11775            let all_selections_inside_invalidation_ranges =
11776                if selections.len() == region.ranges().len() {
11777                    selections
11778                        .iter()
11779                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
11780                        .all(|(selection, invalidation_range)| {
11781                            let head = selection.head().to_offset(buffer);
11782                            invalidation_range.start <= head && invalidation_range.end >= head
11783                        })
11784                } else {
11785                    false
11786                };
11787
11788            if all_selections_inside_invalidation_ranges {
11789                break;
11790            } else {
11791                self.pop();
11792            }
11793        }
11794    }
11795}
11796
11797impl<T> Default for InvalidationStack<T> {
11798    fn default() -> Self {
11799        Self(Default::default())
11800    }
11801}
11802
11803impl<T> Deref for InvalidationStack<T> {
11804    type Target = Vec<T>;
11805
11806    fn deref(&self) -> &Self::Target {
11807        &self.0
11808    }
11809}
11810
11811impl<T> DerefMut for InvalidationStack<T> {
11812    fn deref_mut(&mut self) -> &mut Self::Target {
11813        &mut self.0
11814    }
11815}
11816
11817impl InvalidationRegion for SnippetState {
11818    fn ranges(&self) -> &[Range<Anchor>] {
11819        &self.ranges[self.active_index]
11820    }
11821}
11822
11823pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> RenderBlock {
11824    let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic);
11825
11826    Box::new(move |cx: &mut BlockContext| {
11827        let group_id: SharedString = cx.block_id.to_string().into();
11828
11829        let mut text_style = cx.text_style().clone();
11830        text_style.color = diagnostic_style(diagnostic.severity, true, cx.theme().status());
11831        let theme_settings = ThemeSettings::get_global(cx);
11832        text_style.font_family = theme_settings.buffer_font.family.clone();
11833        text_style.font_style = theme_settings.buffer_font.style;
11834        text_style.font_features = theme_settings.buffer_font.features.clone();
11835        text_style.font_weight = theme_settings.buffer_font.weight;
11836
11837        let multi_line_diagnostic = diagnostic.message.contains('\n');
11838
11839        let buttons = |diagnostic: &Diagnostic, block_id: usize| {
11840            if multi_line_diagnostic {
11841                v_flex()
11842            } else {
11843                h_flex()
11844            }
11845            .children(diagnostic.is_primary.then(|| {
11846                IconButton::new(("close-block", block_id), IconName::XCircle)
11847                    .icon_color(Color::Muted)
11848                    .size(ButtonSize::Compact)
11849                    .style(ButtonStyle::Transparent)
11850                    .visible_on_hover(group_id.clone())
11851                    .on_click(move |_click, cx| cx.dispatch_action(Box::new(Cancel)))
11852                    .tooltip(|cx| Tooltip::for_action("Close Diagnostics", &Cancel, cx))
11853            }))
11854            .child(
11855                IconButton::new(("copy-block", block_id), IconName::Copy)
11856                    .icon_color(Color::Muted)
11857                    .size(ButtonSize::Compact)
11858                    .style(ButtonStyle::Transparent)
11859                    .visible_on_hover(group_id.clone())
11860                    .on_click({
11861                        let message = diagnostic.message.clone();
11862                        move |_click, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
11863                    })
11864                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
11865            )
11866        };
11867
11868        let icon_size = buttons(&diagnostic, cx.block_id)
11869            .into_any_element()
11870            .layout_as_root(AvailableSpace::min_size(), cx);
11871
11872        h_flex()
11873            .id(cx.block_id)
11874            .group(group_id.clone())
11875            .relative()
11876            .size_full()
11877            .pl(cx.gutter_dimensions.width)
11878            .w(cx.max_width + cx.gutter_dimensions.width)
11879            .child(
11880                div()
11881                    .flex()
11882                    .w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
11883                    .flex_shrink(),
11884            )
11885            .child(buttons(&diagnostic, cx.block_id))
11886            .child(div().flex().flex_shrink_0().child(
11887                StyledText::new(text_without_backticks.clone()).with_highlights(
11888                    &text_style,
11889                    code_ranges.iter().map(|range| {
11890                        (
11891                            range.clone(),
11892                            HighlightStyle {
11893                                font_weight: Some(FontWeight::BOLD),
11894                                ..Default::default()
11895                            },
11896                        )
11897                    }),
11898                ),
11899            ))
11900            .into_any_element()
11901    })
11902}
11903
11904pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
11905    let mut text_without_backticks = String::new();
11906    let mut code_ranges = Vec::new();
11907
11908    if let Some(source) = &diagnostic.source {
11909        text_without_backticks.push_str(&source);
11910        code_ranges.push(0..source.len());
11911        text_without_backticks.push_str(": ");
11912    }
11913
11914    let mut prev_offset = 0;
11915    let mut in_code_block = false;
11916    for (ix, _) in diagnostic
11917        .message
11918        .match_indices('`')
11919        .chain([(diagnostic.message.len(), "")])
11920    {
11921        let prev_len = text_without_backticks.len();
11922        text_without_backticks.push_str(&diagnostic.message[prev_offset..ix]);
11923        prev_offset = ix + 1;
11924        if in_code_block {
11925            code_ranges.push(prev_len..text_without_backticks.len());
11926            in_code_block = false;
11927        } else {
11928            in_code_block = true;
11929        }
11930    }
11931
11932    (text_without_backticks.into(), code_ranges)
11933}
11934
11935fn diagnostic_style(severity: DiagnosticSeverity, valid: bool, colors: &StatusColors) -> Hsla {
11936    match (severity, valid) {
11937        (DiagnosticSeverity::ERROR, true) => colors.error,
11938        (DiagnosticSeverity::ERROR, false) => colors.error,
11939        (DiagnosticSeverity::WARNING, true) => colors.warning,
11940        (DiagnosticSeverity::WARNING, false) => colors.warning,
11941        (DiagnosticSeverity::INFORMATION, true) => colors.info,
11942        (DiagnosticSeverity::INFORMATION, false) => colors.info,
11943        (DiagnosticSeverity::HINT, true) => colors.info,
11944        (DiagnosticSeverity::HINT, false) => colors.info,
11945        _ => colors.ignored,
11946    }
11947}
11948
11949pub fn styled_runs_for_code_label<'a>(
11950    label: &'a CodeLabel,
11951    syntax_theme: &'a theme::SyntaxTheme,
11952) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
11953    let fade_out = HighlightStyle {
11954        fade_out: Some(0.35),
11955        ..Default::default()
11956    };
11957
11958    let mut prev_end = label.filter_range.end;
11959    label
11960        .runs
11961        .iter()
11962        .enumerate()
11963        .flat_map(move |(ix, (range, highlight_id))| {
11964            let style = if let Some(style) = highlight_id.style(syntax_theme) {
11965                style
11966            } else {
11967                return Default::default();
11968            };
11969            let mut muted_style = style;
11970            muted_style.highlight(fade_out);
11971
11972            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
11973            if range.start >= label.filter_range.end {
11974                if range.start > prev_end {
11975                    runs.push((prev_end..range.start, fade_out));
11976                }
11977                runs.push((range.clone(), muted_style));
11978            } else if range.end <= label.filter_range.end {
11979                runs.push((range.clone(), style));
11980            } else {
11981                runs.push((range.start..label.filter_range.end, style));
11982                runs.push((label.filter_range.end..range.end, muted_style));
11983            }
11984            prev_end = cmp::max(prev_end, range.end);
11985
11986            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
11987                runs.push((prev_end..label.text.len(), fade_out));
11988            }
11989
11990            runs
11991        })
11992}
11993
11994pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
11995    let mut prev_index = 0;
11996    let mut prev_codepoint: Option<char> = None;
11997    text.char_indices()
11998        .chain([(text.len(), '\0')])
11999        .filter_map(move |(index, codepoint)| {
12000            let prev_codepoint = prev_codepoint.replace(codepoint)?;
12001            let is_boundary = index == text.len()
12002                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
12003                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
12004            if is_boundary {
12005                let chunk = &text[prev_index..index];
12006                prev_index = index;
12007                Some(chunk)
12008            } else {
12009                None
12010            }
12011        })
12012}
12013
12014trait RangeToAnchorExt {
12015    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
12016}
12017
12018impl<T: ToOffset> RangeToAnchorExt for Range<T> {
12019    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
12020        let start_offset = self.start.to_offset(snapshot);
12021        let end_offset = self.end.to_offset(snapshot);
12022        if start_offset == end_offset {
12023            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
12024        } else {
12025            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
12026        }
12027    }
12028}
12029
12030pub trait RowExt {
12031    fn as_f32(&self) -> f32;
12032
12033    fn next_row(&self) -> Self;
12034
12035    fn previous_row(&self) -> Self;
12036
12037    fn minus(&self, other: Self) -> u32;
12038}
12039
12040impl RowExt for DisplayRow {
12041    fn as_f32(&self) -> f32 {
12042        self.0 as f32
12043    }
12044
12045    fn next_row(&self) -> Self {
12046        Self(self.0 + 1)
12047    }
12048
12049    fn previous_row(&self) -> Self {
12050        Self(self.0.saturating_sub(1))
12051    }
12052
12053    fn minus(&self, other: Self) -> u32 {
12054        self.0 - other.0
12055    }
12056}
12057
12058impl RowExt for MultiBufferRow {
12059    fn as_f32(&self) -> f32 {
12060        self.0 as f32
12061    }
12062
12063    fn next_row(&self) -> Self {
12064        Self(self.0 + 1)
12065    }
12066
12067    fn previous_row(&self) -> Self {
12068        Self(self.0.saturating_sub(1))
12069    }
12070
12071    fn minus(&self, other: Self) -> u32 {
12072        self.0 - other.0
12073    }
12074}
12075
12076trait RowRangeExt {
12077    type Row;
12078
12079    fn len(&self) -> usize;
12080
12081    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
12082}
12083
12084impl RowRangeExt for Range<MultiBufferRow> {
12085    type Row = MultiBufferRow;
12086
12087    fn len(&self) -> usize {
12088        (self.end.0 - self.start.0) as usize
12089    }
12090
12091    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
12092        (self.start.0..self.end.0).map(MultiBufferRow)
12093    }
12094}
12095
12096impl RowRangeExt for Range<DisplayRow> {
12097    type Row = DisplayRow;
12098
12099    fn len(&self) -> usize {
12100        (self.end.0 - self.start.0) as usize
12101    }
12102
12103    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
12104        (self.start.0..self.end.0).map(DisplayRow)
12105    }
12106}
12107
12108fn hunk_status(hunk: &DiffHunk<MultiBufferRow>) -> DiffHunkStatus {
12109    if hunk.diff_base_byte_range.is_empty() {
12110        DiffHunkStatus::Added
12111    } else if hunk.associated_range.is_empty() {
12112        DiffHunkStatus::Removed
12113    } else {
12114        DiffHunkStatus::Modified
12115    }
12116}