editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blame_entry_tooltip;
   17mod blink_manager;
   18mod debounced_delay;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26mod hover_popover;
   27mod hunk_diff;
   28mod indent_guides;
   29mod inlay_hint_cache;
   30mod inline_completion_provider;
   31pub mod items;
   32mod linked_editing_ranges;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod editor_tests;
   43mod signature_help;
   44#[cfg(any(test, feature = "test-support"))]
   45pub mod test;
   46
   47use ::git::diff::{DiffHunk, DiffHunkStatus};
   48use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
   49pub(crate) use actions::*;
   50use aho_corasick::AhoCorasick;
   51use anyhow::{anyhow, Context as _, Result};
   52use blink_manager::BlinkManager;
   53use client::{Collaborator, ParticipantIndex};
   54use clock::ReplicaId;
   55use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
   56use convert_case::{Case, Casing};
   57use debounced_delay::DebouncedDelay;
   58use display_map::*;
   59pub use display_map::{DisplayPoint, FoldPlaceholder};
   60pub use editor_settings::{CurrentLineHighlight, EditorSettings};
   61pub use editor_settings_controls::*;
   62use element::LineWithInvisibles;
   63pub use element::{
   64    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   65};
   66use futures::FutureExt;
   67use fuzzy::{StringMatch, StringMatchCandidate};
   68use git::blame::GitBlame;
   69use git::diff_hunk_to_display;
   70use gpui::{
   71    div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
   72    AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
   73    ClipboardItem, Context, DispatchPhase, ElementId, EntityId, EventEmitter, FocusHandle,
   74    FocusOutEvent, FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText,
   75    KeyContext, ListSizingBehavior, Model, MouseButton, PaintQuad, ParentElement, Pixels, Render,
   76    SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle,
   77    UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext,
   78    WeakFocusHandle, WeakView, WindowContext,
   79};
   80use highlight_matching_bracket::refresh_matching_bracket_highlights;
   81use hover_popover::{hide_hover, HoverState};
   82use hunk_diff::ExpandedHunks;
   83pub(crate) use hunk_diff::HoveredHunk;
   84use indent_guides::ActiveIndentGuidesState;
   85use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
   86pub use inline_completion_provider::*;
   87pub use items::MAX_TAB_TITLE_LEN;
   88use itertools::Itertools;
   89use language::{
   90    char_kind,
   91    language_settings::{self, all_language_settings, InlayHintSettings},
   92    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
   93    CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
   94    Point, Selection, SelectionGoal, TransactionId,
   95};
   96use language::{point_to_lsp, BufferRow, Runnable, RunnableRange};
   97use linked_editing_ranges::refresh_linked_ranges;
   98use task::{ResolvedTask, TaskTemplate, TaskVariables};
   99
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
  101pub use lsp::CompletionContext;
  102use lsp::{
  103    CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat,
  104    LanguageServerId,
  105};
  106use mouse_context_menu::MouseContextMenu;
  107use movement::TextLayoutDetails;
  108pub use multi_buffer::{
  109    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
  110    ToPoint,
  111};
  112use multi_buffer::{ExpandExcerptDirection, MultiBufferPoint, MultiBufferRow, ToOffsetUtf16};
  113use ordered_float::OrderedFloat;
  114use parking_lot::{Mutex, RwLock};
  115use project::project_settings::{GitGutterSetting, ProjectSettings};
  116use project::{
  117    CodeAction, Completion, CompletionIntent, FormatTrigger, Item, Location, Project, ProjectPath,
  118    ProjectTransaction, TaskSourceKind, WorktreeId,
  119};
  120use rand::prelude::*;
  121use rpc::{proto::*, ErrorExt};
  122use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  123use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
  124use serde::{Deserialize, Serialize};
  125use settings::{update_settings_file, Settings, SettingsStore};
  126use smallvec::SmallVec;
  127use snippet::Snippet;
  128use std::{
  129    any::TypeId,
  130    borrow::Cow,
  131    cell::RefCell,
  132    cmp::{self, Ordering, Reverse},
  133    mem,
  134    num::NonZeroU32,
  135    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  136    path::{Path, PathBuf},
  137    rc::Rc,
  138    sync::Arc,
  139    time::{Duration, Instant},
  140};
  141pub use sum_tree::Bias;
  142use sum_tree::TreeMap;
  143use text::{BufferId, OffsetUtf16, Rope};
  144use theme::{
  145    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  146    ThemeColors, ThemeSettings,
  147};
  148use ui::{
  149    h_flex, prelude::*, ButtonSize, ButtonStyle, Disclosure, IconButton, IconName, IconSize,
  150    ListItem, Popover, Tooltip,
  151};
  152use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  153use workspace::item::{ItemHandle, PreviewTabsSettings};
  154use workspace::notifications::{DetachAndPromptErr, NotificationId};
  155use workspace::{
  156    searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
  157};
  158use workspace::{OpenInTerminal, OpenTerminal, TabBarSettings, Toast};
  159
  160use crate::hover_links::find_url;
  161use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  162
  163pub const FILE_HEADER_HEIGHT: u32 = 1;
  164pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  165pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
  166pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  167const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  168const MAX_LINE_LEN: usize = 1024;
  169const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  170const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  171pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  172#[doc(hidden)]
  173pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  174#[doc(hidden)]
  175pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  176
  177pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
  178pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  179
  180pub fn render_parsed_markdown(
  181    element_id: impl Into<ElementId>,
  182    parsed: &language::ParsedMarkdown,
  183    editor_style: &EditorStyle,
  184    workspace: Option<WeakView<Workspace>>,
  185    cx: &mut WindowContext,
  186) -> InteractiveText {
  187    let code_span_background_color = cx
  188        .theme()
  189        .colors()
  190        .editor_document_highlight_read_background;
  191
  192    let highlights = gpui::combine_highlights(
  193        parsed.highlights.iter().filter_map(|(range, highlight)| {
  194            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
  195            Some((range.clone(), highlight))
  196        }),
  197        parsed
  198            .regions
  199            .iter()
  200            .zip(&parsed.region_ranges)
  201            .filter_map(|(region, range)| {
  202                if region.code {
  203                    Some((
  204                        range.clone(),
  205                        HighlightStyle {
  206                            background_color: Some(code_span_background_color),
  207                            ..Default::default()
  208                        },
  209                    ))
  210                } else {
  211                    None
  212                }
  213            }),
  214    );
  215
  216    let mut links = Vec::new();
  217    let mut link_ranges = Vec::new();
  218    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
  219        if let Some(link) = region.link.clone() {
  220            links.push(link);
  221            link_ranges.push(range.clone());
  222        }
  223    }
  224
  225    InteractiveText::new(
  226        element_id,
  227        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
  228    )
  229    .on_click(link_ranges, move |clicked_range_ix, cx| {
  230        match &links[clicked_range_ix] {
  231            markdown::Link::Web { url } => cx.open_url(url),
  232            markdown::Link::Path { path } => {
  233                if let Some(workspace) = &workspace {
  234                    _ = workspace.update(cx, |workspace, cx| {
  235                        workspace.open_abs_path(path.clone(), false, cx).detach();
  236                    });
  237                }
  238            }
  239        }
  240    })
  241}
  242
  243#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  244pub(crate) enum InlayId {
  245    Suggestion(usize),
  246    Hint(usize),
  247}
  248
  249impl InlayId {
  250    fn id(&self) -> usize {
  251        match self {
  252            Self::Suggestion(id) => *id,
  253            Self::Hint(id) => *id,
  254        }
  255    }
  256}
  257
  258enum DiffRowHighlight {}
  259enum DocumentHighlightRead {}
  260enum DocumentHighlightWrite {}
  261enum InputComposition {}
  262
  263#[derive(Copy, Clone, PartialEq, Eq)]
  264pub enum Direction {
  265    Prev,
  266    Next,
  267}
  268
  269#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  270pub enum Navigated {
  271    Yes,
  272    No,
  273}
  274
  275impl Navigated {
  276    pub fn from_bool(yes: bool) -> Navigated {
  277        if yes {
  278            Navigated::Yes
  279        } else {
  280            Navigated::No
  281        }
  282    }
  283}
  284
  285pub fn init_settings(cx: &mut AppContext) {
  286    EditorSettings::register(cx);
  287}
  288
  289pub fn init(cx: &mut AppContext) {
  290    init_settings(cx);
  291
  292    workspace::register_project_item::<Editor>(cx);
  293    workspace::FollowableViewRegistry::register::<Editor>(cx);
  294    workspace::register_serializable_item::<Editor>(cx);
  295
  296    cx.observe_new_views(
  297        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  298            workspace.register_action(Editor::new_file);
  299            workspace.register_action(Editor::new_file_in_direction);
  300        },
  301    )
  302    .detach();
  303
  304    cx.on_action(move |_: &workspace::NewFile, cx| {
  305        let app_state = workspace::AppState::global(cx);
  306        if let Some(app_state) = app_state.upgrade() {
  307            workspace::open_new(app_state, cx, |workspace, cx| {
  308                Editor::new_file(workspace, &Default::default(), cx)
  309            })
  310            .detach();
  311        }
  312    });
  313    cx.on_action(move |_: &workspace::NewWindow, cx| {
  314        let app_state = workspace::AppState::global(cx);
  315        if let Some(app_state) = app_state.upgrade() {
  316            workspace::open_new(app_state, cx, |workspace, cx| {
  317                Editor::new_file(workspace, &Default::default(), cx)
  318            })
  319            .detach();
  320        }
  321    });
  322}
  323
  324pub struct SearchWithinRange;
  325
  326trait InvalidationRegion {
  327    fn ranges(&self) -> &[Range<Anchor>];
  328}
  329
  330#[derive(Clone, Debug, PartialEq)]
  331pub enum SelectPhase {
  332    Begin {
  333        position: DisplayPoint,
  334        add: bool,
  335        click_count: usize,
  336    },
  337    BeginColumnar {
  338        position: DisplayPoint,
  339        reset: bool,
  340        goal_column: u32,
  341    },
  342    Extend {
  343        position: DisplayPoint,
  344        click_count: usize,
  345    },
  346    Update {
  347        position: DisplayPoint,
  348        goal_column: u32,
  349        scroll_delta: gpui::Point<f32>,
  350    },
  351    End,
  352}
  353
  354#[derive(Clone, Debug)]
  355pub enum SelectMode {
  356    Character,
  357    Word(Range<Anchor>),
  358    Line(Range<Anchor>),
  359    All,
  360}
  361
  362#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  363pub enum EditorMode {
  364    SingleLine { auto_width: bool },
  365    AutoHeight { max_lines: usize },
  366    Full,
  367}
  368
  369#[derive(Clone, Debug)]
  370pub enum SoftWrap {
  371    None,
  372    PreferLine,
  373    EditorWidth,
  374    Column(u32),
  375}
  376
  377#[derive(Clone)]
  378pub struct EditorStyle {
  379    pub background: Hsla,
  380    pub local_player: PlayerColor,
  381    pub text: TextStyle,
  382    pub scrollbar_width: Pixels,
  383    pub syntax: Arc<SyntaxTheme>,
  384    pub status: StatusColors,
  385    pub inlay_hints_style: HighlightStyle,
  386    pub suggestions_style: HighlightStyle,
  387    pub unnecessary_code_fade: f32,
  388}
  389
  390impl Default for EditorStyle {
  391    fn default() -> Self {
  392        Self {
  393            background: Hsla::default(),
  394            local_player: PlayerColor::default(),
  395            text: TextStyle::default(),
  396            scrollbar_width: Pixels::default(),
  397            syntax: Default::default(),
  398            // HACK: Status colors don't have a real default.
  399            // We should look into removing the status colors from the editor
  400            // style and retrieve them directly from the theme.
  401            status: StatusColors::dark(),
  402            inlay_hints_style: HighlightStyle::default(),
  403            suggestions_style: HighlightStyle::default(),
  404            unnecessary_code_fade: Default::default(),
  405        }
  406    }
  407}
  408
  409type CompletionId = usize;
  410
  411#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  412struct EditorActionId(usize);
  413
  414impl EditorActionId {
  415    pub fn post_inc(&mut self) -> Self {
  416        let answer = self.0;
  417
  418        *self = Self(answer + 1);
  419
  420        Self(answer)
  421    }
  422}
  423
  424// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  425// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  426
  427type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  428type GutterHighlight = (fn(&AppContext) -> Hsla, Arc<[Range<Anchor>]>);
  429
  430#[derive(Default)]
  431struct ScrollbarMarkerState {
  432    scrollbar_size: Size<Pixels>,
  433    dirty: bool,
  434    markers: Arc<[PaintQuad]>,
  435    pending_refresh: Option<Task<Result<()>>>,
  436}
  437
  438impl ScrollbarMarkerState {
  439    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  440        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  441    }
  442}
  443
  444#[derive(Clone, Debug)]
  445struct RunnableTasks {
  446    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  447    offset: MultiBufferOffset,
  448    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  449    column: u32,
  450    // Values of all named captures, including those starting with '_'
  451    extra_variables: HashMap<String, String>,
  452    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  453    context_range: Range<BufferOffset>,
  454}
  455
  456#[derive(Clone)]
  457struct ResolvedTasks {
  458    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  459    position: Anchor,
  460}
  461#[derive(Copy, Clone, Debug)]
  462struct MultiBufferOffset(usize);
  463#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  464struct BufferOffset(usize);
  465
  466// Addons allow storing per-editor state in other crates (e.g. Vim)
  467pub trait Addon: 'static {
  468    fn extend_key_context(&self, _: &mut KeyContext, _: &AppContext) {}
  469
  470    fn to_any(&self) -> &dyn std::any::Any;
  471}
  472
  473/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
  474///
  475/// See the [module level documentation](self) for more information.
  476pub struct Editor {
  477    focus_handle: FocusHandle,
  478    last_focused_descendant: Option<WeakFocusHandle>,
  479    /// The text buffer being edited
  480    buffer: Model<MultiBuffer>,
  481    /// Map of how text in the buffer should be displayed.
  482    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  483    pub display_map: Model<DisplayMap>,
  484    pub selections: SelectionsCollection,
  485    pub scroll_manager: ScrollManager,
  486    /// When inline assist editors are linked, they all render cursors because
  487    /// typing enters text into each of them, even the ones that aren't focused.
  488    pub(crate) show_cursor_when_unfocused: bool,
  489    columnar_selection_tail: Option<Anchor>,
  490    add_selections_state: Option<AddSelectionsState>,
  491    select_next_state: Option<SelectNextState>,
  492    select_prev_state: Option<SelectNextState>,
  493    selection_history: SelectionHistory,
  494    autoclose_regions: Vec<AutocloseRegion>,
  495    snippet_stack: InvalidationStack<SnippetState>,
  496    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  497    ime_transaction: Option<TransactionId>,
  498    active_diagnostics: Option<ActiveDiagnosticGroup>,
  499    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  500    project: Option<Model<Project>>,
  501    completion_provider: Option<Box<dyn CompletionProvider>>,
  502    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  503    blink_manager: Model<BlinkManager>,
  504    show_cursor_names: bool,
  505    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  506    pub show_local_selections: bool,
  507    mode: EditorMode,
  508    show_breadcrumbs: bool,
  509    show_gutter: bool,
  510    show_line_numbers: Option<bool>,
  511    show_git_diff_gutter: Option<bool>,
  512    show_code_actions: Option<bool>,
  513    show_runnables: Option<bool>,
  514    show_wrap_guides: Option<bool>,
  515    show_indent_guides: Option<bool>,
  516    placeholder_text: Option<Arc<str>>,
  517    highlight_order: usize,
  518    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  519    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  520    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  521    scrollbar_marker_state: ScrollbarMarkerState,
  522    active_indent_guides_state: ActiveIndentGuidesState,
  523    nav_history: Option<ItemNavHistory>,
  524    context_menu: RwLock<Option<ContextMenu>>,
  525    mouse_context_menu: Option<MouseContextMenu>,
  526    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  527    signature_help_state: SignatureHelpState,
  528    auto_signature_help: Option<bool>,
  529    find_all_references_task_sources: Vec<Anchor>,
  530    next_completion_id: CompletionId,
  531    completion_documentation_pre_resolve_debounce: DebouncedDelay,
  532    available_code_actions: Option<(Location, Arc<[CodeAction]>)>,
  533    code_actions_task: Option<Task<()>>,
  534    document_highlights_task: Option<Task<()>>,
  535    linked_editing_range_task: Option<Task<Option<()>>>,
  536    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  537    pending_rename: Option<RenameState>,
  538    searchable: bool,
  539    cursor_shape: CursorShape,
  540    current_line_highlight: Option<CurrentLineHighlight>,
  541    collapse_matches: bool,
  542    autoindent_mode: Option<AutoindentMode>,
  543    workspace: Option<(WeakView<Workspace>, Option<WorkspaceId>)>,
  544    input_enabled: bool,
  545    use_modal_editing: bool,
  546    read_only: bool,
  547    leader_peer_id: Option<PeerId>,
  548    remote_id: Option<ViewId>,
  549    hover_state: HoverState,
  550    gutter_hovered: bool,
  551    hovered_link_state: Option<HoveredLinkState>,
  552    inline_completion_provider: Option<RegisteredInlineCompletionProvider>,
  553    active_inline_completion: Option<(Inlay, Option<Range<Anchor>>)>,
  554    show_inline_completions: bool,
  555    inlay_hint_cache: InlayHintCache,
  556    expanded_hunks: ExpandedHunks,
  557    next_inlay_id: usize,
  558    _subscriptions: Vec<Subscription>,
  559    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  560    gutter_dimensions: GutterDimensions,
  561    style: Option<EditorStyle>,
  562    next_editor_action_id: EditorActionId,
  563    editor_actions: Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut ViewContext<Self>)>>>>,
  564    use_autoclose: bool,
  565    use_auto_surround: bool,
  566    auto_replace_emoji_shortcode: bool,
  567    show_git_blame_gutter: bool,
  568    show_git_blame_inline: bool,
  569    show_git_blame_inline_delay_task: Option<Task<()>>,
  570    git_blame_inline_enabled: bool,
  571    serialize_dirty_buffers: bool,
  572    show_selection_menu: Option<bool>,
  573    blame: Option<Model<GitBlame>>,
  574    blame_subscription: Option<Subscription>,
  575    custom_context_menu: Option<
  576        Box<
  577            dyn 'static
  578                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
  579        >,
  580    >,
  581    last_bounds: Option<Bounds<Pixels>>,
  582    expect_bounds_change: Option<Bounds<Pixels>>,
  583    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  584    tasks_update_task: Option<Task<()>>,
  585    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  586    file_header_size: u32,
  587    breadcrumb_header: Option<String>,
  588    focused_block: Option<FocusedBlock>,
  589    next_scroll_position: NextScrollCursorCenterTopBottom,
  590    addons: HashMap<TypeId, Box<dyn Addon>>,
  591    _scroll_cursor_center_top_bottom_task: Task<()>,
  592}
  593
  594#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  595enum NextScrollCursorCenterTopBottom {
  596    #[default]
  597    Center,
  598    Top,
  599    Bottom,
  600}
  601
  602impl NextScrollCursorCenterTopBottom {
  603    fn next(&self) -> Self {
  604        match self {
  605            Self::Center => Self::Top,
  606            Self::Top => Self::Bottom,
  607            Self::Bottom => Self::Center,
  608        }
  609    }
  610}
  611
  612#[derive(Clone)]
  613pub struct EditorSnapshot {
  614    pub mode: EditorMode,
  615    show_gutter: bool,
  616    show_line_numbers: Option<bool>,
  617    show_git_diff_gutter: Option<bool>,
  618    show_code_actions: Option<bool>,
  619    show_runnables: Option<bool>,
  620    render_git_blame_gutter: bool,
  621    pub display_snapshot: DisplaySnapshot,
  622    pub placeholder_text: Option<Arc<str>>,
  623    is_focused: bool,
  624    scroll_anchor: ScrollAnchor,
  625    ongoing_scroll: OngoingScroll,
  626    current_line_highlight: CurrentLineHighlight,
  627    gutter_hovered: bool,
  628}
  629
  630const GIT_BLAME_GUTTER_WIDTH_CHARS: f32 = 53.;
  631
  632#[derive(Default, Debug, Clone, Copy)]
  633pub struct GutterDimensions {
  634    pub left_padding: Pixels,
  635    pub right_padding: Pixels,
  636    pub width: Pixels,
  637    pub margin: Pixels,
  638    pub git_blame_entries_width: Option<Pixels>,
  639}
  640
  641impl GutterDimensions {
  642    /// The full width of the space taken up by the gutter.
  643    pub fn full_width(&self) -> Pixels {
  644        self.margin + self.width
  645    }
  646
  647    /// The width of the space reserved for the fold indicators,
  648    /// use alongside 'justify_end' and `gutter_width` to
  649    /// right align content with the line numbers
  650    pub fn fold_area_width(&self) -> Pixels {
  651        self.margin + self.right_padding
  652    }
  653}
  654
  655#[derive(Debug)]
  656pub struct RemoteSelection {
  657    pub replica_id: ReplicaId,
  658    pub selection: Selection<Anchor>,
  659    pub cursor_shape: CursorShape,
  660    pub peer_id: PeerId,
  661    pub line_mode: bool,
  662    pub participant_index: Option<ParticipantIndex>,
  663    pub user_name: Option<SharedString>,
  664}
  665
  666#[derive(Clone, Debug)]
  667struct SelectionHistoryEntry {
  668    selections: Arc<[Selection<Anchor>]>,
  669    select_next_state: Option<SelectNextState>,
  670    select_prev_state: Option<SelectNextState>,
  671    add_selections_state: Option<AddSelectionsState>,
  672}
  673
  674enum SelectionHistoryMode {
  675    Normal,
  676    Undoing,
  677    Redoing,
  678}
  679
  680#[derive(Clone, PartialEq, Eq, Hash)]
  681struct HoveredCursor {
  682    replica_id: u16,
  683    selection_id: usize,
  684}
  685
  686impl Default for SelectionHistoryMode {
  687    fn default() -> Self {
  688        Self::Normal
  689    }
  690}
  691
  692#[derive(Default)]
  693struct SelectionHistory {
  694    #[allow(clippy::type_complexity)]
  695    selections_by_transaction:
  696        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  697    mode: SelectionHistoryMode,
  698    undo_stack: VecDeque<SelectionHistoryEntry>,
  699    redo_stack: VecDeque<SelectionHistoryEntry>,
  700}
  701
  702impl SelectionHistory {
  703    fn insert_transaction(
  704        &mut self,
  705        transaction_id: TransactionId,
  706        selections: Arc<[Selection<Anchor>]>,
  707    ) {
  708        self.selections_by_transaction
  709            .insert(transaction_id, (selections, None));
  710    }
  711
  712    #[allow(clippy::type_complexity)]
  713    fn transaction(
  714        &self,
  715        transaction_id: TransactionId,
  716    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  717        self.selections_by_transaction.get(&transaction_id)
  718    }
  719
  720    #[allow(clippy::type_complexity)]
  721    fn transaction_mut(
  722        &mut self,
  723        transaction_id: TransactionId,
  724    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  725        self.selections_by_transaction.get_mut(&transaction_id)
  726    }
  727
  728    fn push(&mut self, entry: SelectionHistoryEntry) {
  729        if !entry.selections.is_empty() {
  730            match self.mode {
  731                SelectionHistoryMode::Normal => {
  732                    self.push_undo(entry);
  733                    self.redo_stack.clear();
  734                }
  735                SelectionHistoryMode::Undoing => self.push_redo(entry),
  736                SelectionHistoryMode::Redoing => self.push_undo(entry),
  737            }
  738        }
  739    }
  740
  741    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  742        if self
  743            .undo_stack
  744            .back()
  745            .map_or(true, |e| e.selections != entry.selections)
  746        {
  747            self.undo_stack.push_back(entry);
  748            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  749                self.undo_stack.pop_front();
  750            }
  751        }
  752    }
  753
  754    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  755        if self
  756            .redo_stack
  757            .back()
  758            .map_or(true, |e| e.selections != entry.selections)
  759        {
  760            self.redo_stack.push_back(entry);
  761            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  762                self.redo_stack.pop_front();
  763            }
  764        }
  765    }
  766}
  767
  768struct RowHighlight {
  769    index: usize,
  770    range: RangeInclusive<Anchor>,
  771    color: Option<Hsla>,
  772    should_autoscroll: bool,
  773}
  774
  775#[derive(Clone, Debug)]
  776struct AddSelectionsState {
  777    above: bool,
  778    stack: Vec<usize>,
  779}
  780
  781#[derive(Clone)]
  782struct SelectNextState {
  783    query: AhoCorasick,
  784    wordwise: bool,
  785    done: bool,
  786}
  787
  788impl std::fmt::Debug for SelectNextState {
  789    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  790        f.debug_struct(std::any::type_name::<Self>())
  791            .field("wordwise", &self.wordwise)
  792            .field("done", &self.done)
  793            .finish()
  794    }
  795}
  796
  797#[derive(Debug)]
  798struct AutocloseRegion {
  799    selection_id: usize,
  800    range: Range<Anchor>,
  801    pair: BracketPair,
  802}
  803
  804#[derive(Debug)]
  805struct SnippetState {
  806    ranges: Vec<Vec<Range<Anchor>>>,
  807    active_index: usize,
  808}
  809
  810#[doc(hidden)]
  811pub struct RenameState {
  812    pub range: Range<Anchor>,
  813    pub old_name: Arc<str>,
  814    pub editor: View<Editor>,
  815    block_id: CustomBlockId,
  816}
  817
  818struct InvalidationStack<T>(Vec<T>);
  819
  820struct RegisteredInlineCompletionProvider {
  821    provider: Arc<dyn InlineCompletionProviderHandle>,
  822    _subscription: Subscription,
  823}
  824
  825enum ContextMenu {
  826    Completions(CompletionsMenu),
  827    CodeActions(CodeActionsMenu),
  828}
  829
  830impl ContextMenu {
  831    fn select_first(
  832        &mut self,
  833        project: Option<&Model<Project>>,
  834        cx: &mut ViewContext<Editor>,
  835    ) -> bool {
  836        if self.visible() {
  837            match self {
  838                ContextMenu::Completions(menu) => menu.select_first(project, cx),
  839                ContextMenu::CodeActions(menu) => menu.select_first(cx),
  840            }
  841            true
  842        } else {
  843            false
  844        }
  845    }
  846
  847    fn select_prev(
  848        &mut self,
  849        project: Option<&Model<Project>>,
  850        cx: &mut ViewContext<Editor>,
  851    ) -> bool {
  852        if self.visible() {
  853            match self {
  854                ContextMenu::Completions(menu) => menu.select_prev(project, cx),
  855                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  856            }
  857            true
  858        } else {
  859            false
  860        }
  861    }
  862
  863    fn select_next(
  864        &mut self,
  865        project: Option<&Model<Project>>,
  866        cx: &mut ViewContext<Editor>,
  867    ) -> bool {
  868        if self.visible() {
  869            match self {
  870                ContextMenu::Completions(menu) => menu.select_next(project, cx),
  871                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  872            }
  873            true
  874        } else {
  875            false
  876        }
  877    }
  878
  879    fn select_last(
  880        &mut self,
  881        project: Option<&Model<Project>>,
  882        cx: &mut ViewContext<Editor>,
  883    ) -> bool {
  884        if self.visible() {
  885            match self {
  886                ContextMenu::Completions(menu) => menu.select_last(project, cx),
  887                ContextMenu::CodeActions(menu) => menu.select_last(cx),
  888            }
  889            true
  890        } else {
  891            false
  892        }
  893    }
  894
  895    fn visible(&self) -> bool {
  896        match self {
  897            ContextMenu::Completions(menu) => menu.visible(),
  898            ContextMenu::CodeActions(menu) => menu.visible(),
  899        }
  900    }
  901
  902    fn render(
  903        &self,
  904        cursor_position: DisplayPoint,
  905        style: &EditorStyle,
  906        max_height: Pixels,
  907        workspace: Option<WeakView<Workspace>>,
  908        cx: &mut ViewContext<Editor>,
  909    ) -> (ContextMenuOrigin, AnyElement) {
  910        match self {
  911            ContextMenu::Completions(menu) => (
  912                ContextMenuOrigin::EditorPoint(cursor_position),
  913                menu.render(style, max_height, workspace, cx),
  914            ),
  915            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
  916        }
  917    }
  918}
  919
  920enum ContextMenuOrigin {
  921    EditorPoint(DisplayPoint),
  922    GutterIndicator(DisplayRow),
  923}
  924
  925#[derive(Clone)]
  926struct CompletionsMenu {
  927    id: CompletionId,
  928    sort_completions: bool,
  929    initial_position: Anchor,
  930    buffer: Model<Buffer>,
  931    completions: Arc<RwLock<Box<[Completion]>>>,
  932    match_candidates: Arc<[StringMatchCandidate]>,
  933    matches: Arc<[StringMatch]>,
  934    selected_item: usize,
  935    scroll_handle: UniformListScrollHandle,
  936    selected_completion_documentation_resolve_debounce: Arc<Mutex<DebouncedDelay>>,
  937}
  938
  939impl CompletionsMenu {
  940    fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  941        self.selected_item = 0;
  942        self.scroll_handle.scroll_to_item(self.selected_item);
  943        self.attempt_resolve_selected_completion_documentation(project, cx);
  944        cx.notify();
  945    }
  946
  947    fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  948        if self.selected_item > 0 {
  949            self.selected_item -= 1;
  950        } else {
  951            self.selected_item = self.matches.len() - 1;
  952        }
  953        self.scroll_handle.scroll_to_item(self.selected_item);
  954        self.attempt_resolve_selected_completion_documentation(project, cx);
  955        cx.notify();
  956    }
  957
  958    fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  959        if self.selected_item + 1 < self.matches.len() {
  960            self.selected_item += 1;
  961        } else {
  962            self.selected_item = 0;
  963        }
  964        self.scroll_handle.scroll_to_item(self.selected_item);
  965        self.attempt_resolve_selected_completion_documentation(project, cx);
  966        cx.notify();
  967    }
  968
  969    fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  970        self.selected_item = self.matches.len() - 1;
  971        self.scroll_handle.scroll_to_item(self.selected_item);
  972        self.attempt_resolve_selected_completion_documentation(project, cx);
  973        cx.notify();
  974    }
  975
  976    fn pre_resolve_completion_documentation(
  977        buffer: Model<Buffer>,
  978        completions: Arc<RwLock<Box<[Completion]>>>,
  979        matches: Arc<[StringMatch]>,
  980        editor: &Editor,
  981        cx: &mut ViewContext<Editor>,
  982    ) -> Task<()> {
  983        let settings = EditorSettings::get_global(cx);
  984        if !settings.show_completion_documentation {
  985            return Task::ready(());
  986        }
  987
  988        let Some(provider) = editor.completion_provider.as_ref() else {
  989            return Task::ready(());
  990        };
  991
  992        let resolve_task = provider.resolve_completions(
  993            buffer,
  994            matches.iter().map(|m| m.candidate_id).collect(),
  995            completions.clone(),
  996            cx,
  997        );
  998
  999        return cx.spawn(move |this, mut cx| async move {
 1000            if let Some(true) = resolve_task.await.log_err() {
 1001                this.update(&mut cx, |_, cx| cx.notify()).ok();
 1002            }
 1003        });
 1004    }
 1005
 1006    fn attempt_resolve_selected_completion_documentation(
 1007        &mut self,
 1008        project: Option<&Model<Project>>,
 1009        cx: &mut ViewContext<Editor>,
 1010    ) {
 1011        let settings = EditorSettings::get_global(cx);
 1012        if !settings.show_completion_documentation {
 1013            return;
 1014        }
 1015
 1016        let completion_index = self.matches[self.selected_item].candidate_id;
 1017        let Some(project) = project else {
 1018            return;
 1019        };
 1020
 1021        let resolve_task = project.update(cx, |project, cx| {
 1022            project.resolve_completions(
 1023                self.buffer.clone(),
 1024                vec![completion_index],
 1025                self.completions.clone(),
 1026                cx,
 1027            )
 1028        });
 1029
 1030        let delay_ms =
 1031            EditorSettings::get_global(cx).completion_documentation_secondary_query_debounce;
 1032        let delay = Duration::from_millis(delay_ms);
 1033
 1034        self.selected_completion_documentation_resolve_debounce
 1035            .lock()
 1036            .fire_new(delay, cx, |_, cx| {
 1037                cx.spawn(move |this, mut cx| async move {
 1038                    if let Some(true) = resolve_task.await.log_err() {
 1039                        this.update(&mut cx, |_, cx| cx.notify()).ok();
 1040                    }
 1041                })
 1042            });
 1043    }
 1044
 1045    fn visible(&self) -> bool {
 1046        !self.matches.is_empty()
 1047    }
 1048
 1049    fn render(
 1050        &self,
 1051        style: &EditorStyle,
 1052        max_height: Pixels,
 1053        workspace: Option<WeakView<Workspace>>,
 1054        cx: &mut ViewContext<Editor>,
 1055    ) -> AnyElement {
 1056        let settings = EditorSettings::get_global(cx);
 1057        let show_completion_documentation = settings.show_completion_documentation;
 1058
 1059        let widest_completion_ix = self
 1060            .matches
 1061            .iter()
 1062            .enumerate()
 1063            .max_by_key(|(_, mat)| {
 1064                let completions = self.completions.read();
 1065                let completion = &completions[mat.candidate_id];
 1066                let documentation = &completion.documentation;
 1067
 1068                let mut len = completion.label.text.chars().count();
 1069                if let Some(Documentation::SingleLine(text)) = documentation {
 1070                    if show_completion_documentation {
 1071                        len += text.chars().count();
 1072                    }
 1073                }
 1074
 1075                len
 1076            })
 1077            .map(|(ix, _)| ix);
 1078
 1079        let completions = self.completions.clone();
 1080        let matches = self.matches.clone();
 1081        let selected_item = self.selected_item;
 1082        let style = style.clone();
 1083
 1084        let multiline_docs = if show_completion_documentation {
 1085            let mat = &self.matches[selected_item];
 1086            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
 1087                Some(Documentation::MultiLinePlainText(text)) => {
 1088                    Some(div().child(SharedString::from(text.clone())))
 1089                }
 1090                Some(Documentation::MultiLineMarkdown(parsed)) if !parsed.text.is_empty() => {
 1091                    Some(div().child(render_parsed_markdown(
 1092                        "completions_markdown",
 1093                        parsed,
 1094                        &style,
 1095                        workspace,
 1096                        cx,
 1097                    )))
 1098                }
 1099                _ => None,
 1100            };
 1101            multiline_docs.map(|div| {
 1102                div.id("multiline_docs")
 1103                    .max_h(max_height)
 1104                    .flex_1()
 1105                    .px_1p5()
 1106                    .py_1()
 1107                    .min_w(px(260.))
 1108                    .max_w(px(640.))
 1109                    .w(px(500.))
 1110                    .overflow_y_scroll()
 1111                    .occlude()
 1112            })
 1113        } else {
 1114            None
 1115        };
 1116
 1117        let list = uniform_list(
 1118            cx.view().clone(),
 1119            "completions",
 1120            matches.len(),
 1121            move |_editor, range, cx| {
 1122                let start_ix = range.start;
 1123                let completions_guard = completions.read();
 1124
 1125                matches[range]
 1126                    .iter()
 1127                    .enumerate()
 1128                    .map(|(ix, mat)| {
 1129                        let item_ix = start_ix + ix;
 1130                        let candidate_id = mat.candidate_id;
 1131                        let completion = &completions_guard[candidate_id];
 1132
 1133                        let documentation = if show_completion_documentation {
 1134                            &completion.documentation
 1135                        } else {
 1136                            &None
 1137                        };
 1138
 1139                        let highlights = gpui::combine_highlights(
 1140                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
 1141                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
 1142                                |(range, mut highlight)| {
 1143                                    // Ignore font weight for syntax highlighting, as we'll use it
 1144                                    // for fuzzy matches.
 1145                                    highlight.font_weight = None;
 1146
 1147                                    if completion.lsp_completion.deprecated.unwrap_or(false) {
 1148                                        highlight.strikethrough = Some(StrikethroughStyle {
 1149                                            thickness: 1.0.into(),
 1150                                            ..Default::default()
 1151                                        });
 1152                                        highlight.color = Some(cx.theme().colors().text_muted);
 1153                                    }
 1154
 1155                                    (range, highlight)
 1156                                },
 1157                            ),
 1158                        );
 1159                        let completion_label = StyledText::new(completion.label.text.clone())
 1160                            .with_highlights(&style.text, highlights);
 1161                        let documentation_label =
 1162                            if let Some(Documentation::SingleLine(text)) = documentation {
 1163                                if text.trim().is_empty() {
 1164                                    None
 1165                                } else {
 1166                                    Some(
 1167                                        Label::new(text.clone())
 1168                                            .ml_4()
 1169                                            .size(LabelSize::Small)
 1170                                            .color(Color::Muted),
 1171                                    )
 1172                                }
 1173                            } else {
 1174                                None
 1175                            };
 1176
 1177                        div().min_w(px(220.)).max_w(px(540.)).child(
 1178                            ListItem::new(mat.candidate_id)
 1179                                .inset(true)
 1180                                .selected(item_ix == selected_item)
 1181                                .on_click(cx.listener(move |editor, _event, cx| {
 1182                                    cx.stop_propagation();
 1183                                    if let Some(task) = editor.confirm_completion(
 1184                                        &ConfirmCompletion {
 1185                                            item_ix: Some(item_ix),
 1186                                        },
 1187                                        cx,
 1188                                    ) {
 1189                                        task.detach_and_log_err(cx)
 1190                                    }
 1191                                }))
 1192                                .child(h_flex().overflow_hidden().child(completion_label))
 1193                                .end_slot::<Label>(documentation_label),
 1194                        )
 1195                    })
 1196                    .collect()
 1197            },
 1198        )
 1199        .occlude()
 1200        .max_h(max_height)
 1201        .track_scroll(self.scroll_handle.clone())
 1202        .with_width_from_item(widest_completion_ix)
 1203        .with_sizing_behavior(ListSizingBehavior::Infer);
 1204
 1205        Popover::new()
 1206            .child(list)
 1207            .when_some(multiline_docs, |popover, multiline_docs| {
 1208                popover.aside(multiline_docs)
 1209            })
 1210            .into_any_element()
 1211    }
 1212
 1213    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
 1214        let mut matches = if let Some(query) = query {
 1215            fuzzy::match_strings(
 1216                &self.match_candidates,
 1217                query,
 1218                query.chars().any(|c| c.is_uppercase()),
 1219                100,
 1220                &Default::default(),
 1221                executor,
 1222            )
 1223            .await
 1224        } else {
 1225            self.match_candidates
 1226                .iter()
 1227                .enumerate()
 1228                .map(|(candidate_id, candidate)| StringMatch {
 1229                    candidate_id,
 1230                    score: Default::default(),
 1231                    positions: Default::default(),
 1232                    string: candidate.string.clone(),
 1233                })
 1234                .collect()
 1235        };
 1236
 1237        // Remove all candidates where the query's start does not match the start of any word in the candidate
 1238        if let Some(query) = query {
 1239            if let Some(query_start) = query.chars().next() {
 1240                matches.retain(|string_match| {
 1241                    split_words(&string_match.string).any(|word| {
 1242                        // Check that the first codepoint of the word as lowercase matches the first
 1243                        // codepoint of the query as lowercase
 1244                        word.chars()
 1245                            .flat_map(|codepoint| codepoint.to_lowercase())
 1246                            .zip(query_start.to_lowercase())
 1247                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 1248                    })
 1249                });
 1250            }
 1251        }
 1252
 1253        let completions = self.completions.read();
 1254        if self.sort_completions {
 1255            matches.sort_unstable_by_key(|mat| {
 1256                // We do want to strike a balance here between what the language server tells us
 1257                // to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
 1258                // `Creat` and there is a local variable called `CreateComponent`).
 1259                // So what we do is: we bucket all matches into two buckets
 1260                // - Strong matches
 1261                // - Weak matches
 1262                // Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
 1263                // and the Weak matches are the rest.
 1264                //
 1265                // For the strong matches, we sort by the language-servers score first and for the weak
 1266                // matches, we prefer our fuzzy finder first.
 1267                //
 1268                // The thinking behind that: it's useless to take the sort_text the language-server gives
 1269                // us into account when it's obviously a bad match.
 1270
 1271                #[derive(PartialEq, Eq, PartialOrd, Ord)]
 1272                enum MatchScore<'a> {
 1273                    Strong {
 1274                        sort_text: Option<&'a str>,
 1275                        score: Reverse<OrderedFloat<f64>>,
 1276                        sort_key: (usize, &'a str),
 1277                    },
 1278                    Weak {
 1279                        score: Reverse<OrderedFloat<f64>>,
 1280                        sort_text: Option<&'a str>,
 1281                        sort_key: (usize, &'a str),
 1282                    },
 1283                }
 1284
 1285                let completion = &completions[mat.candidate_id];
 1286                let sort_key = completion.sort_key();
 1287                let sort_text = completion.lsp_completion.sort_text.as_deref();
 1288                let score = Reverse(OrderedFloat(mat.score));
 1289
 1290                if mat.score >= 0.2 {
 1291                    MatchScore::Strong {
 1292                        sort_text,
 1293                        score,
 1294                        sort_key,
 1295                    }
 1296                } else {
 1297                    MatchScore::Weak {
 1298                        score,
 1299                        sort_text,
 1300                        sort_key,
 1301                    }
 1302                }
 1303            });
 1304        }
 1305
 1306        for mat in &mut matches {
 1307            let completion = &completions[mat.candidate_id];
 1308            mat.string.clone_from(&completion.label.text);
 1309            for position in &mut mat.positions {
 1310                *position += completion.label.filter_range.start;
 1311            }
 1312        }
 1313        drop(completions);
 1314
 1315        self.matches = matches.into();
 1316        self.selected_item = 0;
 1317    }
 1318}
 1319
 1320#[derive(Clone)]
 1321struct CodeActionContents {
 1322    tasks: Option<Arc<ResolvedTasks>>,
 1323    actions: Option<Arc<[CodeAction]>>,
 1324}
 1325
 1326impl CodeActionContents {
 1327    fn len(&self) -> usize {
 1328        match (&self.tasks, &self.actions) {
 1329            (Some(tasks), Some(actions)) => actions.len() + tasks.templates.len(),
 1330            (Some(tasks), None) => tasks.templates.len(),
 1331            (None, Some(actions)) => actions.len(),
 1332            (None, None) => 0,
 1333        }
 1334    }
 1335
 1336    fn is_empty(&self) -> bool {
 1337        match (&self.tasks, &self.actions) {
 1338            (Some(tasks), Some(actions)) => actions.is_empty() && tasks.templates.is_empty(),
 1339            (Some(tasks), None) => tasks.templates.is_empty(),
 1340            (None, Some(actions)) => actions.is_empty(),
 1341            (None, None) => true,
 1342        }
 1343    }
 1344
 1345    fn iter(&self) -> impl Iterator<Item = CodeActionsItem> + '_ {
 1346        self.tasks
 1347            .iter()
 1348            .flat_map(|tasks| {
 1349                tasks
 1350                    .templates
 1351                    .iter()
 1352                    .map(|(kind, task)| CodeActionsItem::Task(kind.clone(), task.clone()))
 1353            })
 1354            .chain(self.actions.iter().flat_map(|actions| {
 1355                actions
 1356                    .iter()
 1357                    .map(|action| CodeActionsItem::CodeAction(action.clone()))
 1358            }))
 1359    }
 1360    fn get(&self, index: usize) -> Option<CodeActionsItem> {
 1361        match (&self.tasks, &self.actions) {
 1362            (Some(tasks), Some(actions)) => {
 1363                if index < tasks.templates.len() {
 1364                    tasks
 1365                        .templates
 1366                        .get(index)
 1367                        .cloned()
 1368                        .map(|(kind, task)| CodeActionsItem::Task(kind, task))
 1369                } else {
 1370                    actions
 1371                        .get(index - tasks.templates.len())
 1372                        .cloned()
 1373                        .map(CodeActionsItem::CodeAction)
 1374                }
 1375            }
 1376            (Some(tasks), None) => tasks
 1377                .templates
 1378                .get(index)
 1379                .cloned()
 1380                .map(|(kind, task)| CodeActionsItem::Task(kind, task)),
 1381            (None, Some(actions)) => actions.get(index).cloned().map(CodeActionsItem::CodeAction),
 1382            (None, None) => None,
 1383        }
 1384    }
 1385}
 1386
 1387#[allow(clippy::large_enum_variant)]
 1388#[derive(Clone)]
 1389enum CodeActionsItem {
 1390    Task(TaskSourceKind, ResolvedTask),
 1391    CodeAction(CodeAction),
 1392}
 1393
 1394impl CodeActionsItem {
 1395    fn as_task(&self) -> Option<&ResolvedTask> {
 1396        let Self::Task(_, task) = self else {
 1397            return None;
 1398        };
 1399        Some(task)
 1400    }
 1401    fn as_code_action(&self) -> Option<&CodeAction> {
 1402        let Self::CodeAction(action) = self else {
 1403            return None;
 1404        };
 1405        Some(action)
 1406    }
 1407    fn label(&self) -> String {
 1408        match self {
 1409            Self::CodeAction(action) => action.lsp_action.title.clone(),
 1410            Self::Task(_, task) => task.resolved_label.clone(),
 1411        }
 1412    }
 1413}
 1414
 1415struct CodeActionsMenu {
 1416    actions: CodeActionContents,
 1417    buffer: Model<Buffer>,
 1418    selected_item: usize,
 1419    scroll_handle: UniformListScrollHandle,
 1420    deployed_from_indicator: Option<DisplayRow>,
 1421}
 1422
 1423impl CodeActionsMenu {
 1424    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
 1425        self.selected_item = 0;
 1426        self.scroll_handle.scroll_to_item(self.selected_item);
 1427        cx.notify()
 1428    }
 1429
 1430    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 1431        if self.selected_item > 0 {
 1432            self.selected_item -= 1;
 1433        } else {
 1434            self.selected_item = self.actions.len() - 1;
 1435        }
 1436        self.scroll_handle.scroll_to_item(self.selected_item);
 1437        cx.notify();
 1438    }
 1439
 1440    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 1441        if self.selected_item + 1 < self.actions.len() {
 1442            self.selected_item += 1;
 1443        } else {
 1444            self.selected_item = 0;
 1445        }
 1446        self.scroll_handle.scroll_to_item(self.selected_item);
 1447        cx.notify();
 1448    }
 1449
 1450    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
 1451        self.selected_item = self.actions.len() - 1;
 1452        self.scroll_handle.scroll_to_item(self.selected_item);
 1453        cx.notify()
 1454    }
 1455
 1456    fn visible(&self) -> bool {
 1457        !self.actions.is_empty()
 1458    }
 1459
 1460    fn render(
 1461        &self,
 1462        cursor_position: DisplayPoint,
 1463        _style: &EditorStyle,
 1464        max_height: Pixels,
 1465        cx: &mut ViewContext<Editor>,
 1466    ) -> (ContextMenuOrigin, AnyElement) {
 1467        let actions = self.actions.clone();
 1468        let selected_item = self.selected_item;
 1469        let element = uniform_list(
 1470            cx.view().clone(),
 1471            "code_actions_menu",
 1472            self.actions.len(),
 1473            move |_this, range, cx| {
 1474                actions
 1475                    .iter()
 1476                    .skip(range.start)
 1477                    .take(range.end - range.start)
 1478                    .enumerate()
 1479                    .map(|(ix, action)| {
 1480                        let item_ix = range.start + ix;
 1481                        let selected = selected_item == item_ix;
 1482                        let colors = cx.theme().colors();
 1483                        div()
 1484                            .px_2()
 1485                            .text_color(colors.text)
 1486                            .when(selected, |style| {
 1487                                style
 1488                                    .bg(colors.element_active)
 1489                                    .text_color(colors.text_accent)
 1490                            })
 1491                            .hover(|style| {
 1492                                style
 1493                                    .bg(colors.element_hover)
 1494                                    .text_color(colors.text_accent)
 1495                            })
 1496                            .whitespace_nowrap()
 1497                            .when_some(action.as_code_action(), |this, action| {
 1498                                this.on_mouse_down(
 1499                                    MouseButton::Left,
 1500                                    cx.listener(move |editor, _, cx| {
 1501                                        cx.stop_propagation();
 1502                                        if let Some(task) = editor.confirm_code_action(
 1503                                            &ConfirmCodeAction {
 1504                                                item_ix: Some(item_ix),
 1505                                            },
 1506                                            cx,
 1507                                        ) {
 1508                                            task.detach_and_log_err(cx)
 1509                                        }
 1510                                    }),
 1511                                )
 1512                                // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
 1513                                .child(SharedString::from(action.lsp_action.title.clone()))
 1514                            })
 1515                            .when_some(action.as_task(), |this, task| {
 1516                                this.on_mouse_down(
 1517                                    MouseButton::Left,
 1518                                    cx.listener(move |editor, _, cx| {
 1519                                        cx.stop_propagation();
 1520                                        if let Some(task) = editor.confirm_code_action(
 1521                                            &ConfirmCodeAction {
 1522                                                item_ix: Some(item_ix),
 1523                                            },
 1524                                            cx,
 1525                                        ) {
 1526                                            task.detach_and_log_err(cx)
 1527                                        }
 1528                                    }),
 1529                                )
 1530                                .child(SharedString::from(task.resolved_label.clone()))
 1531                            })
 1532                    })
 1533                    .collect()
 1534            },
 1535        )
 1536        .elevation_1(cx)
 1537        .px_2()
 1538        .py_1()
 1539        .max_h(max_height)
 1540        .occlude()
 1541        .track_scroll(self.scroll_handle.clone())
 1542        .with_width_from_item(
 1543            self.actions
 1544                .iter()
 1545                .enumerate()
 1546                .max_by_key(|(_, action)| match action {
 1547                    CodeActionsItem::Task(_, task) => task.resolved_label.chars().count(),
 1548                    CodeActionsItem::CodeAction(action) => action.lsp_action.title.chars().count(),
 1549                })
 1550                .map(|(ix, _)| ix),
 1551        )
 1552        .with_sizing_behavior(ListSizingBehavior::Infer)
 1553        .into_any_element();
 1554
 1555        let cursor_position = if let Some(row) = self.deployed_from_indicator {
 1556            ContextMenuOrigin::GutterIndicator(row)
 1557        } else {
 1558            ContextMenuOrigin::EditorPoint(cursor_position)
 1559        };
 1560
 1561        (cursor_position, element)
 1562    }
 1563}
 1564
 1565#[derive(Debug)]
 1566struct ActiveDiagnosticGroup {
 1567    primary_range: Range<Anchor>,
 1568    primary_message: String,
 1569    group_id: usize,
 1570    blocks: HashMap<CustomBlockId, Diagnostic>,
 1571    is_valid: bool,
 1572}
 1573
 1574#[derive(Serialize, Deserialize, Clone, Debug)]
 1575pub struct ClipboardSelection {
 1576    pub len: usize,
 1577    pub is_entire_line: bool,
 1578    pub first_line_indent: u32,
 1579}
 1580
 1581#[derive(Debug)]
 1582pub(crate) struct NavigationData {
 1583    cursor_anchor: Anchor,
 1584    cursor_position: Point,
 1585    scroll_anchor: ScrollAnchor,
 1586    scroll_top_row: u32,
 1587}
 1588
 1589#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1590enum GotoDefinitionKind {
 1591    Symbol,
 1592    Declaration,
 1593    Type,
 1594    Implementation,
 1595}
 1596
 1597#[derive(Debug, Clone)]
 1598enum InlayHintRefreshReason {
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::Toggle(_) => "toggle",
 1611            Self::SettingsChange(_) => "settings change",
 1612            Self::NewLinesShown => "new lines shown",
 1613            Self::BufferEdited(_) => "buffer edited",
 1614            Self::RefreshRequested => "refresh requested",
 1615            Self::ExcerptsRemoved(_) => "excerpts removed",
 1616        }
 1617    }
 1618}
 1619
 1620pub(crate) struct FocusedBlock {
 1621    id: BlockId,
 1622    focus_handle: WeakFocusHandle,
 1623}
 1624
 1625impl Editor {
 1626    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
 1627        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1628        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1629        Self::new(
 1630            EditorMode::SingleLine { auto_width: false },
 1631            buffer,
 1632            None,
 1633            false,
 1634            cx,
 1635        )
 1636    }
 1637
 1638    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
 1639        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1640        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1641        Self::new(EditorMode::Full, buffer, None, false, cx)
 1642    }
 1643
 1644    pub fn auto_width(cx: &mut ViewContext<Self>) -> Self {
 1645        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1646        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1647        Self::new(
 1648            EditorMode::SingleLine { auto_width: true },
 1649            buffer,
 1650            None,
 1651            false,
 1652            cx,
 1653        )
 1654    }
 1655
 1656    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
 1657        let buffer = cx.new_model(|cx| Buffer::local("", cx));
 1658        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1659        Self::new(
 1660            EditorMode::AutoHeight { max_lines },
 1661            buffer,
 1662            None,
 1663            false,
 1664            cx,
 1665        )
 1666    }
 1667
 1668    pub fn for_buffer(
 1669        buffer: Model<Buffer>,
 1670        project: Option<Model<Project>>,
 1671        cx: &mut ViewContext<Self>,
 1672    ) -> Self {
 1673        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::Full, buffer, project, false, cx)
 1675    }
 1676
 1677    pub fn for_multibuffer(
 1678        buffer: Model<MultiBuffer>,
 1679        project: Option<Model<Project>>,
 1680        show_excerpt_controls: bool,
 1681        cx: &mut ViewContext<Self>,
 1682    ) -> Self {
 1683        Self::new(EditorMode::Full, buffer, project, show_excerpt_controls, cx)
 1684    }
 1685
 1686    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 1687        let show_excerpt_controls = self.display_map.read(cx).show_excerpt_controls();
 1688        let mut clone = Self::new(
 1689            self.mode,
 1690            self.buffer.clone(),
 1691            self.project.clone(),
 1692            show_excerpt_controls,
 1693            cx,
 1694        );
 1695        self.display_map.update(cx, |display_map, cx| {
 1696            let snapshot = display_map.snapshot(cx);
 1697            clone.display_map.update(cx, |display_map, cx| {
 1698                display_map.set_state(&snapshot, cx);
 1699            });
 1700        });
 1701        clone.selections.clone_state(&self.selections);
 1702        clone.scroll_manager.clone_state(&self.scroll_manager);
 1703        clone.searchable = self.searchable;
 1704        clone
 1705    }
 1706
 1707    pub fn new(
 1708        mode: EditorMode,
 1709        buffer: Model<MultiBuffer>,
 1710        project: Option<Model<Project>>,
 1711        show_excerpt_controls: bool,
 1712        cx: &mut ViewContext<Self>,
 1713    ) -> Self {
 1714        let style = cx.text_style();
 1715        let font_size = style.font_size.to_pixels(cx.rem_size());
 1716        let editor = cx.view().downgrade();
 1717        let fold_placeholder = FoldPlaceholder {
 1718            constrain_width: true,
 1719            render: Arc::new(move |fold_id, fold_range, cx| {
 1720                let editor = editor.clone();
 1721                div()
 1722                    .id(fold_id)
 1723                    .bg(cx.theme().colors().ghost_element_background)
 1724                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1725                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1726                    .rounded_sm()
 1727                    .size_full()
 1728                    .cursor_pointer()
 1729                    .child("")
 1730                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 1731                    .on_click(move |_, cx| {
 1732                        editor
 1733                            .update(cx, |editor, cx| {
 1734                                editor.unfold_ranges(
 1735                                    [fold_range.start..fold_range.end],
 1736                                    true,
 1737                                    false,
 1738                                    cx,
 1739                                );
 1740                                cx.stop_propagation();
 1741                            })
 1742                            .ok();
 1743                    })
 1744                    .into_any()
 1745            }),
 1746            merge_adjacent: true,
 1747        };
 1748        let file_header_size = if show_excerpt_controls { 3 } else { 2 };
 1749        let display_map = cx.new_model(|cx| {
 1750            DisplayMap::new(
 1751                buffer.clone(),
 1752                style.font(),
 1753                font_size,
 1754                None,
 1755                show_excerpt_controls,
 1756                file_header_size,
 1757                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1758                MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT,
 1759                fold_placeholder,
 1760                cx,
 1761            )
 1762        });
 1763
 1764        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1765
 1766        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1767
 1768        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1769            .then(|| language_settings::SoftWrap::PreferLine);
 1770
 1771        let mut project_subscriptions = Vec::new();
 1772        if mode == EditorMode::Full {
 1773            if let Some(project) = project.as_ref() {
 1774                if buffer.read(cx).is_singleton() {
 1775                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
 1776                        cx.emit(EditorEvent::TitleChanged);
 1777                    }));
 1778                }
 1779                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
 1780                    if let project::Event::RefreshInlayHints = event {
 1781                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1782                    } else if let project::Event::SnippetEdit(id, snippet_edits) = event {
 1783                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1784                            let focus_handle = editor.focus_handle(cx);
 1785                            if focus_handle.is_focused(cx) {
 1786                                let snapshot = buffer.read(cx).snapshot();
 1787                                for (range, snippet) in snippet_edits {
 1788                                    let editor_range =
 1789                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1790                                    editor
 1791                                        .insert_snippet(&[editor_range], snippet.clone(), cx)
 1792                                        .ok();
 1793                                }
 1794                            }
 1795                        }
 1796                    }
 1797                }));
 1798                let task_inventory = project.read(cx).task_inventory().clone();
 1799                project_subscriptions.push(cx.observe(&task_inventory, |editor, _, cx| {
 1800                    editor.tasks_update_task = Some(editor.refresh_runnables(cx));
 1801                }));
 1802            }
 1803        }
 1804
 1805        let inlay_hint_settings = inlay_hint_settings(
 1806            selections.newest_anchor().head(),
 1807            &buffer.read(cx).snapshot(cx),
 1808            cx,
 1809        );
 1810        let focus_handle = cx.focus_handle();
 1811        cx.on_focus(&focus_handle, Self::handle_focus).detach();
 1812        cx.on_focus_in(&focus_handle, Self::handle_focus_in)
 1813            .detach();
 1814        cx.on_focus_out(&focus_handle, Self::handle_focus_out)
 1815            .detach();
 1816        cx.on_blur(&focus_handle, Self::handle_blur).detach();
 1817
 1818        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1819            Some(false)
 1820        } else {
 1821            None
 1822        };
 1823
 1824        let mut this = Self {
 1825            focus_handle,
 1826            show_cursor_when_unfocused: false,
 1827            last_focused_descendant: None,
 1828            buffer: buffer.clone(),
 1829            display_map: display_map.clone(),
 1830            selections,
 1831            scroll_manager: ScrollManager::new(cx),
 1832            columnar_selection_tail: None,
 1833            add_selections_state: None,
 1834            select_next_state: None,
 1835            select_prev_state: None,
 1836            selection_history: Default::default(),
 1837            autoclose_regions: Default::default(),
 1838            snippet_stack: Default::default(),
 1839            select_larger_syntax_node_stack: Vec::new(),
 1840            ime_transaction: Default::default(),
 1841            active_diagnostics: None,
 1842            soft_wrap_mode_override,
 1843            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1844            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1845            project,
 1846            blink_manager: blink_manager.clone(),
 1847            show_local_selections: true,
 1848            mode,
 1849            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1850            show_gutter: mode == EditorMode::Full,
 1851            show_line_numbers: None,
 1852            show_git_diff_gutter: None,
 1853            show_code_actions: None,
 1854            show_runnables: None,
 1855            show_wrap_guides: None,
 1856            show_indent_guides,
 1857            placeholder_text: None,
 1858            highlight_order: 0,
 1859            highlighted_rows: HashMap::default(),
 1860            background_highlights: Default::default(),
 1861            gutter_highlights: TreeMap::default(),
 1862            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1863            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1864            nav_history: None,
 1865            context_menu: RwLock::new(None),
 1866            mouse_context_menu: None,
 1867            completion_tasks: Default::default(),
 1868            signature_help_state: SignatureHelpState::default(),
 1869            auto_signature_help: None,
 1870            find_all_references_task_sources: Vec::new(),
 1871            next_completion_id: 0,
 1872            completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
 1873            next_inlay_id: 0,
 1874            available_code_actions: Default::default(),
 1875            code_actions_task: Default::default(),
 1876            document_highlights_task: Default::default(),
 1877            linked_editing_range_task: Default::default(),
 1878            pending_rename: Default::default(),
 1879            searchable: true,
 1880            cursor_shape: Default::default(),
 1881            current_line_highlight: None,
 1882            autoindent_mode: Some(AutoindentMode::EachLine),
 1883            collapse_matches: false,
 1884            workspace: None,
 1885            input_enabled: true,
 1886            use_modal_editing: mode == EditorMode::Full,
 1887            read_only: false,
 1888            use_autoclose: true,
 1889            use_auto_surround: true,
 1890            auto_replace_emoji_shortcode: false,
 1891            leader_peer_id: None,
 1892            remote_id: None,
 1893            hover_state: Default::default(),
 1894            hovered_link_state: Default::default(),
 1895            inline_completion_provider: None,
 1896            active_inline_completion: None,
 1897            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1898            expanded_hunks: ExpandedHunks::default(),
 1899            gutter_hovered: false,
 1900            pixel_position_of_newest_cursor: None,
 1901            last_bounds: None,
 1902            expect_bounds_change: None,
 1903            gutter_dimensions: GutterDimensions::default(),
 1904            style: None,
 1905            show_cursor_names: false,
 1906            hovered_cursors: Default::default(),
 1907            next_editor_action_id: EditorActionId::default(),
 1908            editor_actions: Rc::default(),
 1909            show_inline_completions: mode == EditorMode::Full,
 1910            custom_context_menu: None,
 1911            show_git_blame_gutter: false,
 1912            show_git_blame_inline: false,
 1913            show_selection_menu: None,
 1914            show_git_blame_inline_delay_task: None,
 1915            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1916            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1917                .session
 1918                .restore_unsaved_buffers,
 1919            blame: None,
 1920            blame_subscription: None,
 1921            file_header_size,
 1922            tasks: Default::default(),
 1923            _subscriptions: vec![
 1924                cx.observe(&buffer, Self::on_buffer_changed),
 1925                cx.subscribe(&buffer, Self::on_buffer_event),
 1926                cx.observe(&display_map, Self::on_display_map_changed),
 1927                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1928                cx.observe_global::<SettingsStore>(Self::settings_changed),
 1929                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1930                cx.observe_window_activation(|editor, cx| {
 1931                    let active = cx.is_window_active();
 1932                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1933                        if active {
 1934                            blink_manager.enable(cx);
 1935                        } else {
 1936                            blink_manager.disable(cx);
 1937                        }
 1938                    });
 1939                }),
 1940            ],
 1941            tasks_update_task: None,
 1942            linked_edit_ranges: Default::default(),
 1943            previous_search_ranges: None,
 1944            breadcrumb_header: None,
 1945            focused_block: None,
 1946            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1947            addons: HashMap::default(),
 1948            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1949        };
 1950        this.tasks_update_task = Some(this.refresh_runnables(cx));
 1951        this._subscriptions.extend(project_subscriptions);
 1952
 1953        this.end_selection(cx);
 1954        this.scroll_manager.show_scrollbar(cx);
 1955
 1956        if mode == EditorMode::Full {
 1957            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1958            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1959
 1960            if this.git_blame_inline_enabled {
 1961                this.git_blame_inline_enabled = true;
 1962                this.start_git_blame_inline(false, cx);
 1963            }
 1964        }
 1965
 1966        this.report_editor_event("open", None, cx);
 1967        this
 1968    }
 1969
 1970    pub fn mouse_menu_is_focused(&self, cx: &WindowContext) -> bool {
 1971        self.mouse_context_menu
 1972            .as_ref()
 1973            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(cx))
 1974    }
 1975
 1976    fn key_context(&self, cx: &ViewContext<Self>) -> KeyContext {
 1977        let mut key_context = KeyContext::new_with_defaults();
 1978        key_context.add("Editor");
 1979        let mode = match self.mode {
 1980            EditorMode::SingleLine { .. } => "single_line",
 1981            EditorMode::AutoHeight { .. } => "auto_height",
 1982            EditorMode::Full => "full",
 1983        };
 1984
 1985        if EditorSettings::jupyter_enabled(cx) {
 1986            key_context.add("jupyter");
 1987        }
 1988
 1989        key_context.set("mode", mode);
 1990        if self.pending_rename.is_some() {
 1991            key_context.add("renaming");
 1992        }
 1993        if self.context_menu_visible() {
 1994            match self.context_menu.read().as_ref() {
 1995                Some(ContextMenu::Completions(_)) => {
 1996                    key_context.add("menu");
 1997                    key_context.add("showing_completions")
 1998                }
 1999                Some(ContextMenu::CodeActions(_)) => {
 2000                    key_context.add("menu");
 2001                    key_context.add("showing_code_actions")
 2002                }
 2003                None => {}
 2004            }
 2005        }
 2006
 2007        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2008        if !self.focus_handle(cx).contains_focused(cx)
 2009            || (self.is_focused(cx) || self.mouse_menu_is_focused(cx))
 2010        {
 2011            for addon in self.addons.values() {
 2012                addon.extend_key_context(&mut key_context, cx)
 2013            }
 2014        }
 2015
 2016        if let Some(extension) = self
 2017            .buffer
 2018            .read(cx)
 2019            .as_singleton()
 2020            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 2021        {
 2022            key_context.set("extension", extension.to_string());
 2023        }
 2024
 2025        if self.has_active_inline_completion(cx) {
 2026            key_context.add("copilot_suggestion");
 2027            key_context.add("inline_completion");
 2028        }
 2029
 2030        key_context
 2031    }
 2032
 2033    pub fn new_file(
 2034        workspace: &mut Workspace,
 2035        _: &workspace::NewFile,
 2036        cx: &mut ViewContext<Workspace>,
 2037    ) {
 2038        Self::new_in_workspace(workspace, cx).detach_and_prompt_err(
 2039            "Failed to create buffer",
 2040            cx,
 2041            |e, _| match e.error_code() {
 2042                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2043                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2044                e.error_tag("required").unwrap_or("the latest version")
 2045            )),
 2046                _ => None,
 2047            },
 2048        );
 2049    }
 2050
 2051    pub fn new_in_workspace(
 2052        workspace: &mut Workspace,
 2053        cx: &mut ViewContext<Workspace>,
 2054    ) -> Task<Result<View<Editor>>> {
 2055        let project = workspace.project().clone();
 2056        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2057
 2058        cx.spawn(|workspace, mut cx| async move {
 2059            let buffer = create.await?;
 2060            workspace.update(&mut cx, |workspace, cx| {
 2061                let editor =
 2062                    cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx));
 2063                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx);
 2064                editor
 2065            })
 2066        })
 2067    }
 2068
 2069    pub fn new_file_in_direction(
 2070        workspace: &mut Workspace,
 2071        action: &workspace::NewFileInDirection,
 2072        cx: &mut ViewContext<Workspace>,
 2073    ) {
 2074        let project = workspace.project().clone();
 2075        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2076        let direction = action.0;
 2077
 2078        cx.spawn(|workspace, mut cx| async move {
 2079            let buffer = create.await?;
 2080            workspace.update(&mut cx, move |workspace, cx| {
 2081                workspace.split_item(
 2082                    direction,
 2083                    Box::new(
 2084                        cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
 2085                    ),
 2086                    cx,
 2087                )
 2088            })?;
 2089            anyhow::Ok(())
 2090        })
 2091        .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
 2092            ErrorCode::RemoteUpgradeRequired => Some(format!(
 2093                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2094                e.error_tag("required").unwrap_or("the latest version")
 2095            )),
 2096            _ => None,
 2097        });
 2098    }
 2099
 2100    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
 2101        self.buffer.read(cx).replica_id()
 2102    }
 2103
 2104    pub fn leader_peer_id(&self) -> Option<PeerId> {
 2105        self.leader_peer_id
 2106    }
 2107
 2108    pub fn buffer(&self) -> &Model<MultiBuffer> {
 2109        &self.buffer
 2110    }
 2111
 2112    pub fn workspace(&self) -> Option<View<Workspace>> {
 2113        self.workspace.as_ref()?.0.upgrade()
 2114    }
 2115
 2116    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
 2117        self.buffer().read(cx).title(cx)
 2118    }
 2119
 2120    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
 2121        EditorSnapshot {
 2122            mode: self.mode,
 2123            show_gutter: self.show_gutter,
 2124            show_line_numbers: self.show_line_numbers,
 2125            show_git_diff_gutter: self.show_git_diff_gutter,
 2126            show_code_actions: self.show_code_actions,
 2127            show_runnables: self.show_runnables,
 2128            render_git_blame_gutter: self.render_git_blame_gutter(cx),
 2129            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2130            scroll_anchor: self.scroll_manager.anchor(),
 2131            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2132            placeholder_text: self.placeholder_text.clone(),
 2133            is_focused: self.focus_handle.is_focused(cx),
 2134            current_line_highlight: self
 2135                .current_line_highlight
 2136                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2137            gutter_hovered: self.gutter_hovered,
 2138        }
 2139    }
 2140
 2141    pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
 2142        self.buffer.read(cx).language_at(point, cx)
 2143    }
 2144
 2145    pub fn file_at<T: ToOffset>(
 2146        &self,
 2147        point: T,
 2148        cx: &AppContext,
 2149    ) -> Option<Arc<dyn language::File>> {
 2150        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2151    }
 2152
 2153    pub fn active_excerpt(
 2154        &self,
 2155        cx: &AppContext,
 2156    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
 2157        self.buffer
 2158            .read(cx)
 2159            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2160    }
 2161
 2162    pub fn mode(&self) -> EditorMode {
 2163        self.mode
 2164    }
 2165
 2166    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2167        self.collaboration_hub.as_deref()
 2168    }
 2169
 2170    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2171        self.collaboration_hub = Some(hub);
 2172    }
 2173
 2174    pub fn set_custom_context_menu(
 2175        &mut self,
 2176        f: impl 'static
 2177            + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
 2178    ) {
 2179        self.custom_context_menu = Some(Box::new(f))
 2180    }
 2181
 2182    pub fn set_completion_provider(&mut self, provider: Box<dyn CompletionProvider>) {
 2183        self.completion_provider = Some(provider);
 2184    }
 2185
 2186    pub fn set_inline_completion_provider<T>(
 2187        &mut self,
 2188        provider: Option<Model<T>>,
 2189        cx: &mut ViewContext<Self>,
 2190    ) where
 2191        T: InlineCompletionProvider,
 2192    {
 2193        self.inline_completion_provider =
 2194            provider.map(|provider| RegisteredInlineCompletionProvider {
 2195                _subscription: cx.observe(&provider, |this, _, cx| {
 2196                    if this.focus_handle.is_focused(cx) {
 2197                        this.update_visible_inline_completion(cx);
 2198                    }
 2199                }),
 2200                provider: Arc::new(provider),
 2201            });
 2202        self.refresh_inline_completion(false, cx);
 2203    }
 2204
 2205    pub fn placeholder_text(&self, _cx: &WindowContext) -> Option<&str> {
 2206        self.placeholder_text.as_deref()
 2207    }
 2208
 2209    pub fn set_placeholder_text(
 2210        &mut self,
 2211        placeholder_text: impl Into<Arc<str>>,
 2212        cx: &mut ViewContext<Self>,
 2213    ) {
 2214        let placeholder_text = Some(placeholder_text.into());
 2215        if self.placeholder_text != placeholder_text {
 2216            self.placeholder_text = placeholder_text;
 2217            cx.notify();
 2218        }
 2219    }
 2220
 2221    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 2222        self.cursor_shape = cursor_shape;
 2223
 2224        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2225        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2226
 2227        cx.notify();
 2228    }
 2229
 2230    pub fn set_current_line_highlight(
 2231        &mut self,
 2232        current_line_highlight: Option<CurrentLineHighlight>,
 2233    ) {
 2234        self.current_line_highlight = current_line_highlight;
 2235    }
 2236
 2237    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2238        self.collapse_matches = collapse_matches;
 2239    }
 2240
 2241    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2242        if self.collapse_matches {
 2243            return range.start..range.start;
 2244        }
 2245        range.clone()
 2246    }
 2247
 2248    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 2249        if self.display_map.read(cx).clip_at_line_ends != clip {
 2250            self.display_map
 2251                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2252        }
 2253    }
 2254
 2255    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2256        self.input_enabled = input_enabled;
 2257    }
 2258
 2259    pub fn set_autoindent(&mut self, autoindent: bool) {
 2260        if autoindent {
 2261            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2262        } else {
 2263            self.autoindent_mode = None;
 2264        }
 2265    }
 2266
 2267    pub fn read_only(&self, cx: &AppContext) -> bool {
 2268        self.read_only || self.buffer.read(cx).read_only()
 2269    }
 2270
 2271    pub fn set_read_only(&mut self, read_only: bool) {
 2272        self.read_only = read_only;
 2273    }
 2274
 2275    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2276        self.use_autoclose = autoclose;
 2277    }
 2278
 2279    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2280        self.use_auto_surround = auto_surround;
 2281    }
 2282
 2283    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2284        self.auto_replace_emoji_shortcode = auto_replace;
 2285    }
 2286
 2287    pub fn set_show_inline_completions(&mut self, show_inline_completions: bool) {
 2288        self.show_inline_completions = show_inline_completions;
 2289    }
 2290
 2291    pub fn set_use_modal_editing(&mut self, to: bool) {
 2292        self.use_modal_editing = to;
 2293    }
 2294
 2295    pub fn use_modal_editing(&self) -> bool {
 2296        self.use_modal_editing
 2297    }
 2298
 2299    fn selections_did_change(
 2300        &mut self,
 2301        local: bool,
 2302        old_cursor_position: &Anchor,
 2303        show_completions: bool,
 2304        cx: &mut ViewContext<Self>,
 2305    ) {
 2306        // Copy selections to primary selection buffer
 2307        #[cfg(target_os = "linux")]
 2308        if local {
 2309            let selections = self.selections.all::<usize>(cx);
 2310            let buffer_handle = self.buffer.read(cx).read(cx);
 2311
 2312            let mut text = String::new();
 2313            for (index, selection) in selections.iter().enumerate() {
 2314                let text_for_selection = buffer_handle
 2315                    .text_for_range(selection.start..selection.end)
 2316                    .collect::<String>();
 2317
 2318                text.push_str(&text_for_selection);
 2319                if index != selections.len() - 1 {
 2320                    text.push('\n');
 2321                }
 2322            }
 2323
 2324            if !text.is_empty() {
 2325                cx.write_to_primary(ClipboardItem::new_string(text));
 2326            }
 2327        }
 2328
 2329        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
 2330            self.buffer.update(cx, |buffer, cx| {
 2331                buffer.set_active_selections(
 2332                    &self.selections.disjoint_anchors(),
 2333                    self.selections.line_mode,
 2334                    self.cursor_shape,
 2335                    cx,
 2336                )
 2337            });
 2338        }
 2339        let display_map = self
 2340            .display_map
 2341            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2342        let buffer = &display_map.buffer_snapshot;
 2343        self.add_selections_state = None;
 2344        self.select_next_state = None;
 2345        self.select_prev_state = None;
 2346        self.select_larger_syntax_node_stack.clear();
 2347        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2348        self.snippet_stack
 2349            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2350        self.take_rename(false, cx);
 2351
 2352        let new_cursor_position = self.selections.newest_anchor().head();
 2353
 2354        self.push_to_nav_history(
 2355            *old_cursor_position,
 2356            Some(new_cursor_position.to_point(buffer)),
 2357            cx,
 2358        );
 2359
 2360        if local {
 2361            let new_cursor_position = self.selections.newest_anchor().head();
 2362            let mut context_menu = self.context_menu.write();
 2363            let completion_menu = match context_menu.as_ref() {
 2364                Some(ContextMenu::Completions(menu)) => Some(menu),
 2365
 2366                _ => {
 2367                    *context_menu = None;
 2368                    None
 2369                }
 2370            };
 2371
 2372            if let Some(completion_menu) = completion_menu {
 2373                let cursor_position = new_cursor_position.to_offset(buffer);
 2374                let (word_range, kind) = buffer.surrounding_word(completion_menu.initial_position);
 2375                if kind == Some(CharKind::Word)
 2376                    && word_range.to_inclusive().contains(&cursor_position)
 2377                {
 2378                    let mut completion_menu = completion_menu.clone();
 2379                    drop(context_menu);
 2380
 2381                    let query = Self::completion_query(buffer, cursor_position);
 2382                    cx.spawn(move |this, mut cx| async move {
 2383                        completion_menu
 2384                            .filter(query.as_deref(), cx.background_executor().clone())
 2385                            .await;
 2386
 2387                        this.update(&mut cx, |this, cx| {
 2388                            let mut context_menu = this.context_menu.write();
 2389                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
 2390                                return;
 2391                            };
 2392
 2393                            if menu.id > completion_menu.id {
 2394                                return;
 2395                            }
 2396
 2397                            *context_menu = Some(ContextMenu::Completions(completion_menu));
 2398                            drop(context_menu);
 2399                            cx.notify();
 2400                        })
 2401                    })
 2402                    .detach();
 2403
 2404                    if show_completions {
 2405                        self.show_completions(&ShowCompletions { trigger: None }, cx);
 2406                    }
 2407                } else {
 2408                    drop(context_menu);
 2409                    self.hide_context_menu(cx);
 2410                }
 2411            } else {
 2412                drop(context_menu);
 2413            }
 2414
 2415            hide_hover(self, cx);
 2416
 2417            if old_cursor_position.to_display_point(&display_map).row()
 2418                != new_cursor_position.to_display_point(&display_map).row()
 2419            {
 2420                self.available_code_actions.take();
 2421            }
 2422            self.refresh_code_actions(cx);
 2423            self.refresh_document_highlights(cx);
 2424            refresh_matching_bracket_highlights(self, cx);
 2425            self.discard_inline_completion(false, cx);
 2426            linked_editing_ranges::refresh_linked_ranges(self, cx);
 2427            if self.git_blame_inline_enabled {
 2428                self.start_inline_blame_timer(cx);
 2429            }
 2430        }
 2431
 2432        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2433        cx.emit(EditorEvent::SelectionsChanged { local });
 2434
 2435        if self.selections.disjoint_anchors().len() == 1 {
 2436            cx.emit(SearchEvent::ActiveMatchChanged)
 2437        }
 2438        cx.notify();
 2439    }
 2440
 2441    pub fn change_selections<R>(
 2442        &mut self,
 2443        autoscroll: Option<Autoscroll>,
 2444        cx: &mut ViewContext<Self>,
 2445        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2446    ) -> R {
 2447        self.change_selections_inner(autoscroll, true, cx, change)
 2448    }
 2449
 2450    pub fn change_selections_inner<R>(
 2451        &mut self,
 2452        autoscroll: Option<Autoscroll>,
 2453        request_completions: bool,
 2454        cx: &mut ViewContext<Self>,
 2455        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2456    ) -> R {
 2457        let old_cursor_position = self.selections.newest_anchor().head();
 2458        self.push_to_selection_history();
 2459
 2460        let (changed, result) = self.selections.change_with(cx, change);
 2461
 2462        if changed {
 2463            if let Some(autoscroll) = autoscroll {
 2464                self.request_autoscroll(autoscroll, cx);
 2465            }
 2466            self.selections_did_change(true, &old_cursor_position, request_completions, cx);
 2467
 2468            if self.should_open_signature_help_automatically(
 2469                &old_cursor_position,
 2470                self.signature_help_state.backspace_pressed(),
 2471                cx,
 2472            ) {
 2473                self.show_signature_help(&ShowSignatureHelp, cx);
 2474            }
 2475            self.signature_help_state.set_backspace_pressed(false);
 2476        }
 2477
 2478        result
 2479    }
 2480
 2481    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2482    where
 2483        I: IntoIterator<Item = (Range<S>, T)>,
 2484        S: ToOffset,
 2485        T: Into<Arc<str>>,
 2486    {
 2487        if self.read_only(cx) {
 2488            return;
 2489        }
 2490
 2491        self.buffer
 2492            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2493    }
 2494
 2495    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2496    where
 2497        I: IntoIterator<Item = (Range<S>, T)>,
 2498        S: ToOffset,
 2499        T: Into<Arc<str>>,
 2500    {
 2501        if self.read_only(cx) {
 2502            return;
 2503        }
 2504
 2505        self.buffer.update(cx, |buffer, cx| {
 2506            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2507        });
 2508    }
 2509
 2510    pub fn edit_with_block_indent<I, S, T>(
 2511        &mut self,
 2512        edits: I,
 2513        original_indent_columns: Vec<u32>,
 2514        cx: &mut ViewContext<Self>,
 2515    ) where
 2516        I: IntoIterator<Item = (Range<S>, T)>,
 2517        S: ToOffset,
 2518        T: Into<Arc<str>>,
 2519    {
 2520        if self.read_only(cx) {
 2521            return;
 2522        }
 2523
 2524        self.buffer.update(cx, |buffer, cx| {
 2525            buffer.edit(
 2526                edits,
 2527                Some(AutoindentMode::Block {
 2528                    original_indent_columns,
 2529                }),
 2530                cx,
 2531            )
 2532        });
 2533    }
 2534
 2535    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
 2536        self.hide_context_menu(cx);
 2537
 2538        match phase {
 2539            SelectPhase::Begin {
 2540                position,
 2541                add,
 2542                click_count,
 2543            } => self.begin_selection(position, add, click_count, cx),
 2544            SelectPhase::BeginColumnar {
 2545                position,
 2546                goal_column,
 2547                reset,
 2548            } => self.begin_columnar_selection(position, goal_column, reset, cx),
 2549            SelectPhase::Extend {
 2550                position,
 2551                click_count,
 2552            } => self.extend_selection(position, click_count, cx),
 2553            SelectPhase::Update {
 2554                position,
 2555                goal_column,
 2556                scroll_delta,
 2557            } => self.update_selection(position, goal_column, scroll_delta, cx),
 2558            SelectPhase::End => self.end_selection(cx),
 2559        }
 2560    }
 2561
 2562    fn extend_selection(
 2563        &mut self,
 2564        position: DisplayPoint,
 2565        click_count: usize,
 2566        cx: &mut ViewContext<Self>,
 2567    ) {
 2568        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2569        let tail = self.selections.newest::<usize>(cx).tail();
 2570        self.begin_selection(position, false, click_count, cx);
 2571
 2572        let position = position.to_offset(&display_map, Bias::Left);
 2573        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2574
 2575        let mut pending_selection = self
 2576            .selections
 2577            .pending_anchor()
 2578            .expect("extend_selection not called with pending selection");
 2579        if position >= tail {
 2580            pending_selection.start = tail_anchor;
 2581        } else {
 2582            pending_selection.end = tail_anchor;
 2583            pending_selection.reversed = true;
 2584        }
 2585
 2586        let mut pending_mode = self.selections.pending_mode().unwrap();
 2587        match &mut pending_mode {
 2588            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2589            _ => {}
 2590        }
 2591
 2592        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2593            s.set_pending(pending_selection, pending_mode)
 2594        });
 2595    }
 2596
 2597    fn begin_selection(
 2598        &mut self,
 2599        position: DisplayPoint,
 2600        add: bool,
 2601        click_count: usize,
 2602        cx: &mut ViewContext<Self>,
 2603    ) {
 2604        if !self.focus_handle.is_focused(cx) {
 2605            self.last_focused_descendant = None;
 2606            cx.focus(&self.focus_handle);
 2607        }
 2608
 2609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2610        let buffer = &display_map.buffer_snapshot;
 2611        let newest_selection = self.selections.newest_anchor().clone();
 2612        let position = display_map.clip_point(position, Bias::Left);
 2613
 2614        let start;
 2615        let end;
 2616        let mode;
 2617        let auto_scroll;
 2618        match click_count {
 2619            1 => {
 2620                start = buffer.anchor_before(position.to_point(&display_map));
 2621                end = start;
 2622                mode = SelectMode::Character;
 2623                auto_scroll = true;
 2624            }
 2625            2 => {
 2626                let range = movement::surrounding_word(&display_map, position);
 2627                start = buffer.anchor_before(range.start.to_point(&display_map));
 2628                end = buffer.anchor_before(range.end.to_point(&display_map));
 2629                mode = SelectMode::Word(start..end);
 2630                auto_scroll = true;
 2631            }
 2632            3 => {
 2633                let position = display_map
 2634                    .clip_point(position, Bias::Left)
 2635                    .to_point(&display_map);
 2636                let line_start = display_map.prev_line_boundary(position).0;
 2637                let next_line_start = buffer.clip_point(
 2638                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2639                    Bias::Left,
 2640                );
 2641                start = buffer.anchor_before(line_start);
 2642                end = buffer.anchor_before(next_line_start);
 2643                mode = SelectMode::Line(start..end);
 2644                auto_scroll = true;
 2645            }
 2646            _ => {
 2647                start = buffer.anchor_before(0);
 2648                end = buffer.anchor_before(buffer.len());
 2649                mode = SelectMode::All;
 2650                auto_scroll = false;
 2651            }
 2652        }
 2653
 2654        let point_to_delete: Option<usize> = {
 2655            let selected_points: Vec<Selection<Point>> =
 2656                self.selections.disjoint_in_range(start..end, cx);
 2657
 2658            if !add || click_count > 1 {
 2659                None
 2660            } else if selected_points.len() > 0 {
 2661                Some(selected_points[0].id)
 2662            } else {
 2663                let clicked_point_already_selected =
 2664                    self.selections.disjoint.iter().find(|selection| {
 2665                        selection.start.to_point(buffer) == start.to_point(buffer)
 2666                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2667                    });
 2668
 2669                if let Some(selection) = clicked_point_already_selected {
 2670                    Some(selection.id)
 2671                } else {
 2672                    None
 2673                }
 2674            }
 2675        };
 2676
 2677        let selections_count = self.selections.count();
 2678
 2679        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
 2680            if let Some(point_to_delete) = point_to_delete {
 2681                s.delete(point_to_delete);
 2682
 2683                if selections_count == 1 {
 2684                    s.set_pending_anchor_range(start..end, mode);
 2685                }
 2686            } else {
 2687                if !add {
 2688                    s.clear_disjoint();
 2689                } else if click_count > 1 {
 2690                    s.delete(newest_selection.id)
 2691                }
 2692
 2693                s.set_pending_anchor_range(start..end, mode);
 2694            }
 2695        });
 2696    }
 2697
 2698    fn begin_columnar_selection(
 2699        &mut self,
 2700        position: DisplayPoint,
 2701        goal_column: u32,
 2702        reset: bool,
 2703        cx: &mut ViewContext<Self>,
 2704    ) {
 2705        if !self.focus_handle.is_focused(cx) {
 2706            self.last_focused_descendant = None;
 2707            cx.focus(&self.focus_handle);
 2708        }
 2709
 2710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2711
 2712        if reset {
 2713            let pointer_position = display_map
 2714                .buffer_snapshot
 2715                .anchor_before(position.to_point(&display_map));
 2716
 2717            self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 2718                s.clear_disjoint();
 2719                s.set_pending_anchor_range(
 2720                    pointer_position..pointer_position,
 2721                    SelectMode::Character,
 2722                );
 2723            });
 2724        }
 2725
 2726        let tail = self.selections.newest::<Point>(cx).tail();
 2727        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2728
 2729        if !reset {
 2730            self.select_columns(
 2731                tail.to_display_point(&display_map),
 2732                position,
 2733                goal_column,
 2734                &display_map,
 2735                cx,
 2736            );
 2737        }
 2738    }
 2739
 2740    fn update_selection(
 2741        &mut self,
 2742        position: DisplayPoint,
 2743        goal_column: u32,
 2744        scroll_delta: gpui::Point<f32>,
 2745        cx: &mut ViewContext<Self>,
 2746    ) {
 2747        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2748
 2749        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2750            let tail = tail.to_display_point(&display_map);
 2751            self.select_columns(tail, position, goal_column, &display_map, cx);
 2752        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2753            let buffer = self.buffer.read(cx).snapshot(cx);
 2754            let head;
 2755            let tail;
 2756            let mode = self.selections.pending_mode().unwrap();
 2757            match &mode {
 2758                SelectMode::Character => {
 2759                    head = position.to_point(&display_map);
 2760                    tail = pending.tail().to_point(&buffer);
 2761                }
 2762                SelectMode::Word(original_range) => {
 2763                    let original_display_range = original_range.start.to_display_point(&display_map)
 2764                        ..original_range.end.to_display_point(&display_map);
 2765                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2766                        ..original_display_range.end.to_point(&display_map);
 2767                    if movement::is_inside_word(&display_map, position)
 2768                        || original_display_range.contains(&position)
 2769                    {
 2770                        let word_range = movement::surrounding_word(&display_map, position);
 2771                        if word_range.start < original_display_range.start {
 2772                            head = word_range.start.to_point(&display_map);
 2773                        } else {
 2774                            head = word_range.end.to_point(&display_map);
 2775                        }
 2776                    } else {
 2777                        head = position.to_point(&display_map);
 2778                    }
 2779
 2780                    if head <= original_buffer_range.start {
 2781                        tail = original_buffer_range.end;
 2782                    } else {
 2783                        tail = original_buffer_range.start;
 2784                    }
 2785                }
 2786                SelectMode::Line(original_range) => {
 2787                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2788
 2789                    let position = display_map
 2790                        .clip_point(position, Bias::Left)
 2791                        .to_point(&display_map);
 2792                    let line_start = display_map.prev_line_boundary(position).0;
 2793                    let next_line_start = buffer.clip_point(
 2794                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2795                        Bias::Left,
 2796                    );
 2797
 2798                    if line_start < original_range.start {
 2799                        head = line_start
 2800                    } else {
 2801                        head = next_line_start
 2802                    }
 2803
 2804                    if head <= original_range.start {
 2805                        tail = original_range.end;
 2806                    } else {
 2807                        tail = original_range.start;
 2808                    }
 2809                }
 2810                SelectMode::All => {
 2811                    return;
 2812                }
 2813            };
 2814
 2815            if head < tail {
 2816                pending.start = buffer.anchor_before(head);
 2817                pending.end = buffer.anchor_before(tail);
 2818                pending.reversed = true;
 2819            } else {
 2820                pending.start = buffer.anchor_before(tail);
 2821                pending.end = buffer.anchor_before(head);
 2822                pending.reversed = false;
 2823            }
 2824
 2825            self.change_selections(None, cx, |s| {
 2826                s.set_pending(pending, mode);
 2827            });
 2828        } else {
 2829            log::error!("update_selection dispatched with no pending selection");
 2830            return;
 2831        }
 2832
 2833        self.apply_scroll_delta(scroll_delta, cx);
 2834        cx.notify();
 2835    }
 2836
 2837    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 2838        self.columnar_selection_tail.take();
 2839        if self.selections.pending_anchor().is_some() {
 2840            let selections = self.selections.all::<usize>(cx);
 2841            self.change_selections(None, cx, |s| {
 2842                s.select(selections);
 2843                s.clear_pending();
 2844            });
 2845        }
 2846    }
 2847
 2848    fn select_columns(
 2849        &mut self,
 2850        tail: DisplayPoint,
 2851        head: DisplayPoint,
 2852        goal_column: u32,
 2853        display_map: &DisplaySnapshot,
 2854        cx: &mut ViewContext<Self>,
 2855    ) {
 2856        let start_row = cmp::min(tail.row(), head.row());
 2857        let end_row = cmp::max(tail.row(), head.row());
 2858        let start_column = cmp::min(tail.column(), goal_column);
 2859        let end_column = cmp::max(tail.column(), goal_column);
 2860        let reversed = start_column < tail.column();
 2861
 2862        let selection_ranges = (start_row.0..=end_row.0)
 2863            .map(DisplayRow)
 2864            .filter_map(|row| {
 2865                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2866                    let start = display_map
 2867                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2868                        .to_point(display_map);
 2869                    let end = display_map
 2870                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2871                        .to_point(display_map);
 2872                    if reversed {
 2873                        Some(end..start)
 2874                    } else {
 2875                        Some(start..end)
 2876                    }
 2877                } else {
 2878                    None
 2879                }
 2880            })
 2881            .collect::<Vec<_>>();
 2882
 2883        self.change_selections(None, cx, |s| {
 2884            s.select_ranges(selection_ranges);
 2885        });
 2886        cx.notify();
 2887    }
 2888
 2889    pub fn has_pending_nonempty_selection(&self) -> bool {
 2890        let pending_nonempty_selection = match self.selections.pending_anchor() {
 2891            Some(Selection { start, end, .. }) => start != end,
 2892            None => false,
 2893        };
 2894
 2895        pending_nonempty_selection
 2896            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 2897    }
 2898
 2899    pub fn has_pending_selection(&self) -> bool {
 2900        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 2901    }
 2902
 2903    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 2904        if self.clear_clicked_diff_hunks(cx) {
 2905            cx.notify();
 2906            return;
 2907        }
 2908        if self.dismiss_menus_and_popups(true, cx) {
 2909            return;
 2910        }
 2911
 2912        if self.mode == EditorMode::Full {
 2913            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
 2914                return;
 2915            }
 2916        }
 2917
 2918        cx.propagate();
 2919    }
 2920
 2921    pub fn dismiss_menus_and_popups(
 2922        &mut self,
 2923        should_report_inline_completion_event: bool,
 2924        cx: &mut ViewContext<Self>,
 2925    ) -> bool {
 2926        if self.take_rename(false, cx).is_some() {
 2927            return true;
 2928        }
 2929
 2930        if hide_hover(self, cx) {
 2931            return true;
 2932        }
 2933
 2934        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 2935            return true;
 2936        }
 2937
 2938        if self.hide_context_menu(cx).is_some() {
 2939            return true;
 2940        }
 2941
 2942        if self.mouse_context_menu.take().is_some() {
 2943            return true;
 2944        }
 2945
 2946        if self.discard_inline_completion(should_report_inline_completion_event, cx) {
 2947            return true;
 2948        }
 2949
 2950        if self.snippet_stack.pop().is_some() {
 2951            return true;
 2952        }
 2953
 2954        if self.mode == EditorMode::Full {
 2955            if self.active_diagnostics.is_some() {
 2956                self.dismiss_diagnostics(cx);
 2957                return true;
 2958            }
 2959        }
 2960
 2961        false
 2962    }
 2963
 2964    fn linked_editing_ranges_for(
 2965        &self,
 2966        selection: Range<text::Anchor>,
 2967        cx: &AppContext,
 2968    ) -> Option<HashMap<Model<Buffer>, Vec<Range<text::Anchor>>>> {
 2969        if self.linked_edit_ranges.is_empty() {
 2970            return None;
 2971        }
 2972        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 2973            selection.end.buffer_id.and_then(|end_buffer_id| {
 2974                if selection.start.buffer_id != Some(end_buffer_id) {
 2975                    return None;
 2976                }
 2977                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 2978                let snapshot = buffer.read(cx).snapshot();
 2979                self.linked_edit_ranges
 2980                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 2981                    .map(|ranges| (ranges, snapshot, buffer))
 2982            })?;
 2983        use text::ToOffset as TO;
 2984        // find offset from the start of current range to current cursor position
 2985        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 2986
 2987        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 2988        let start_difference = start_offset - start_byte_offset;
 2989        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 2990        let end_difference = end_offset - start_byte_offset;
 2991        // Current range has associated linked ranges.
 2992        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 2993        for range in linked_ranges.iter() {
 2994            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 2995            let end_offset = start_offset + end_difference;
 2996            let start_offset = start_offset + start_difference;
 2997            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 2998                continue;
 2999            }
 3000            let start = buffer_snapshot.anchor_after(start_offset);
 3001            let end = buffer_snapshot.anchor_after(end_offset);
 3002            linked_edits
 3003                .entry(buffer.clone())
 3004                .or_default()
 3005                .push(start..end);
 3006        }
 3007        Some(linked_edits)
 3008    }
 3009
 3010    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 3011        let text: Arc<str> = text.into();
 3012
 3013        if self.read_only(cx) {
 3014            return;
 3015        }
 3016
 3017        let selections = self.selections.all_adjusted(cx);
 3018        let mut bracket_inserted = false;
 3019        let mut edits = Vec::new();
 3020        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3021        let mut new_selections = Vec::with_capacity(selections.len());
 3022        let mut new_autoclose_regions = Vec::new();
 3023        let snapshot = self.buffer.read(cx).read(cx);
 3024
 3025        for (selection, autoclose_region) in
 3026            self.selections_with_autoclose_regions(selections, &snapshot)
 3027        {
 3028            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3029                // Determine if the inserted text matches the opening or closing
 3030                // bracket of any of this language's bracket pairs.
 3031                let mut bracket_pair = None;
 3032                let mut is_bracket_pair_start = false;
 3033                let mut is_bracket_pair_end = false;
 3034                if !text.is_empty() {
 3035                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3036                    //  and they are removing the character that triggered IME popup.
 3037                    for (pair, enabled) in scope.brackets() {
 3038                        if !pair.close && !pair.surround {
 3039                            continue;
 3040                        }
 3041
 3042                        if enabled && pair.start.ends_with(text.as_ref()) {
 3043                            bracket_pair = Some(pair.clone());
 3044                            is_bracket_pair_start = true;
 3045                            break;
 3046                        }
 3047                        if pair.end.as_str() == text.as_ref() {
 3048                            bracket_pair = Some(pair.clone());
 3049                            is_bracket_pair_end = true;
 3050                            break;
 3051                        }
 3052                    }
 3053                }
 3054
 3055                if let Some(bracket_pair) = bracket_pair {
 3056                    let snapshot_settings = snapshot.settings_at(selection.start, cx);
 3057                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3058                    let auto_surround =
 3059                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3060                    if selection.is_empty() {
 3061                        if is_bracket_pair_start {
 3062                            let prefix_len = bracket_pair.start.len() - text.len();
 3063
 3064                            // If the inserted text is a suffix of an opening bracket and the
 3065                            // selection is preceded by the rest of the opening bracket, then
 3066                            // insert the closing bracket.
 3067                            let following_text_allows_autoclose = snapshot
 3068                                .chars_at(selection.start)
 3069                                .next()
 3070                                .map_or(true, |c| scope.should_autoclose_before(c));
 3071                            let preceding_text_matches_prefix = prefix_len == 0
 3072                                || (selection.start.column >= (prefix_len as u32)
 3073                                    && snapshot.contains_str_at(
 3074                                        Point::new(
 3075                                            selection.start.row,
 3076                                            selection.start.column - (prefix_len as u32),
 3077                                        ),
 3078                                        &bracket_pair.start[..prefix_len],
 3079                                    ));
 3080
 3081                            if autoclose
 3082                                && bracket_pair.close
 3083                                && following_text_allows_autoclose
 3084                                && preceding_text_matches_prefix
 3085                            {
 3086                                let anchor = snapshot.anchor_before(selection.end);
 3087                                new_selections.push((selection.map(|_| anchor), text.len()));
 3088                                new_autoclose_regions.push((
 3089                                    anchor,
 3090                                    text.len(),
 3091                                    selection.id,
 3092                                    bracket_pair.clone(),
 3093                                ));
 3094                                edits.push((
 3095                                    selection.range(),
 3096                                    format!("{}{}", text, bracket_pair.end).into(),
 3097                                ));
 3098                                bracket_inserted = true;
 3099                                continue;
 3100                            }
 3101                        }
 3102
 3103                        if let Some(region) = autoclose_region {
 3104                            // If the selection is followed by an auto-inserted closing bracket,
 3105                            // then don't insert that closing bracket again; just move the selection
 3106                            // past the closing bracket.
 3107                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3108                                && text.as_ref() == region.pair.end.as_str();
 3109                            if should_skip {
 3110                                let anchor = snapshot.anchor_after(selection.end);
 3111                                new_selections
 3112                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3113                                continue;
 3114                            }
 3115                        }
 3116
 3117                        let always_treat_brackets_as_autoclosed = snapshot
 3118                            .settings_at(selection.start, cx)
 3119                            .always_treat_brackets_as_autoclosed;
 3120                        if always_treat_brackets_as_autoclosed
 3121                            && is_bracket_pair_end
 3122                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3123                        {
 3124                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3125                            // and the inserted text is a closing bracket and the selection is followed
 3126                            // by the closing bracket then move the selection past the closing bracket.
 3127                            let anchor = snapshot.anchor_after(selection.end);
 3128                            new_selections.push((selection.map(|_| anchor), text.len()));
 3129                            continue;
 3130                        }
 3131                    }
 3132                    // If an opening bracket is 1 character long and is typed while
 3133                    // text is selected, then surround that text with the bracket pair.
 3134                    else if auto_surround
 3135                        && bracket_pair.surround
 3136                        && is_bracket_pair_start
 3137                        && bracket_pair.start.chars().count() == 1
 3138                    {
 3139                        edits.push((selection.start..selection.start, text.clone()));
 3140                        edits.push((
 3141                            selection.end..selection.end,
 3142                            bracket_pair.end.as_str().into(),
 3143                        ));
 3144                        bracket_inserted = true;
 3145                        new_selections.push((
 3146                            Selection {
 3147                                id: selection.id,
 3148                                start: snapshot.anchor_after(selection.start),
 3149                                end: snapshot.anchor_before(selection.end),
 3150                                reversed: selection.reversed,
 3151                                goal: selection.goal,
 3152                            },
 3153                            0,
 3154                        ));
 3155                        continue;
 3156                    }
 3157                }
 3158            }
 3159
 3160            if self.auto_replace_emoji_shortcode
 3161                && selection.is_empty()
 3162                && text.as_ref().ends_with(':')
 3163            {
 3164                if let Some(possible_emoji_short_code) =
 3165                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3166                {
 3167                    if !possible_emoji_short_code.is_empty() {
 3168                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3169                            let emoji_shortcode_start = Point::new(
 3170                                selection.start.row,
 3171                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3172                            );
 3173
 3174                            // Remove shortcode from buffer
 3175                            edits.push((
 3176                                emoji_shortcode_start..selection.start,
 3177                                "".to_string().into(),
 3178                            ));
 3179                            new_selections.push((
 3180                                Selection {
 3181                                    id: selection.id,
 3182                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3183                                    end: snapshot.anchor_before(selection.start),
 3184                                    reversed: selection.reversed,
 3185                                    goal: selection.goal,
 3186                                },
 3187                                0,
 3188                            ));
 3189
 3190                            // Insert emoji
 3191                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3192                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3193                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3194
 3195                            continue;
 3196                        }
 3197                    }
 3198                }
 3199            }
 3200
 3201            // If not handling any auto-close operation, then just replace the selected
 3202            // text with the given input and move the selection to the end of the
 3203            // newly inserted text.
 3204            let anchor = snapshot.anchor_after(selection.end);
 3205            if !self.linked_edit_ranges.is_empty() {
 3206                let start_anchor = snapshot.anchor_before(selection.start);
 3207
 3208                let is_word_char = text.chars().next().map_or(true, |char| {
 3209                    let scope = snapshot.language_scope_at(start_anchor.to_offset(&snapshot));
 3210                    let kind = char_kind(&scope, char);
 3211
 3212                    kind == CharKind::Word
 3213                });
 3214
 3215                if is_word_char {
 3216                    if let Some(ranges) = self
 3217                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3218                    {
 3219                        for (buffer, edits) in ranges {
 3220                            linked_edits
 3221                                .entry(buffer.clone())
 3222                                .or_default()
 3223                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3224                        }
 3225                    }
 3226                }
 3227            }
 3228
 3229            new_selections.push((selection.map(|_| anchor), 0));
 3230            edits.push((selection.start..selection.end, text.clone()));
 3231        }
 3232
 3233        drop(snapshot);
 3234
 3235        self.transact(cx, |this, cx| {
 3236            this.buffer.update(cx, |buffer, cx| {
 3237                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3238            });
 3239            for (buffer, edits) in linked_edits {
 3240                buffer.update(cx, |buffer, cx| {
 3241                    let snapshot = buffer.snapshot();
 3242                    let edits = edits
 3243                        .into_iter()
 3244                        .map(|(range, text)| {
 3245                            use text::ToPoint as TP;
 3246                            let end_point = TP::to_point(&range.end, &snapshot);
 3247                            let start_point = TP::to_point(&range.start, &snapshot);
 3248                            (start_point..end_point, text)
 3249                        })
 3250                        .sorted_by_key(|(range, _)| range.start)
 3251                        .collect::<Vec<_>>();
 3252                    buffer.edit(edits, None, cx);
 3253                })
 3254            }
 3255            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3256            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3257            let snapshot = this.buffer.read(cx).read(cx);
 3258            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
 3259                .zip(new_selection_deltas)
 3260                .map(|(selection, delta)| Selection {
 3261                    id: selection.id,
 3262                    start: selection.start + delta,
 3263                    end: selection.end + delta,
 3264                    reversed: selection.reversed,
 3265                    goal: SelectionGoal::None,
 3266                })
 3267                .collect::<Vec<_>>();
 3268
 3269            let mut i = 0;
 3270            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3271                let position = position.to_offset(&snapshot) + delta;
 3272                let start = snapshot.anchor_before(position);
 3273                let end = snapshot.anchor_after(position);
 3274                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3275                    match existing_state.range.start.cmp(&start, &snapshot) {
 3276                        Ordering::Less => i += 1,
 3277                        Ordering::Greater => break,
 3278                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
 3279                            Ordering::Less => i += 1,
 3280                            Ordering::Equal => break,
 3281                            Ordering::Greater => break,
 3282                        },
 3283                    }
 3284                }
 3285                this.autoclose_regions.insert(
 3286                    i,
 3287                    AutocloseRegion {
 3288                        selection_id,
 3289                        range: start..end,
 3290                        pair,
 3291                    },
 3292                );
 3293            }
 3294
 3295            drop(snapshot);
 3296            let had_active_inline_completion = this.has_active_inline_completion(cx);
 3297            this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| {
 3298                s.select(new_selections)
 3299            });
 3300
 3301            if !bracket_inserted && EditorSettings::get_global(cx).use_on_type_format {
 3302                if let Some(on_type_format_task) =
 3303                    this.trigger_on_type_formatting(text.to_string(), cx)
 3304                {
 3305                    on_type_format_task.detach_and_log_err(cx);
 3306                }
 3307            }
 3308
 3309            let editor_settings = EditorSettings::get_global(cx);
 3310            if bracket_inserted
 3311                && (editor_settings.auto_signature_help
 3312                    || editor_settings.show_signature_help_after_edits)
 3313            {
 3314                this.show_signature_help(&ShowSignatureHelp, cx);
 3315            }
 3316
 3317            let trigger_in_words = !had_active_inline_completion;
 3318            this.trigger_completion_on_input(&text, trigger_in_words, cx);
 3319            linked_editing_ranges::refresh_linked_ranges(this, cx);
 3320            this.refresh_inline_completion(true, cx);
 3321        });
 3322    }
 3323
 3324    fn find_possible_emoji_shortcode_at_position(
 3325        snapshot: &MultiBufferSnapshot,
 3326        position: Point,
 3327    ) -> Option<String> {
 3328        let mut chars = Vec::new();
 3329        let mut found_colon = false;
 3330        for char in snapshot.reversed_chars_at(position).take(100) {
 3331            // Found a possible emoji shortcode in the middle of the buffer
 3332            if found_colon {
 3333                if char.is_whitespace() {
 3334                    chars.reverse();
 3335                    return Some(chars.iter().collect());
 3336                }
 3337                // If the previous character is not a whitespace, we are in the middle of a word
 3338                // and we only want to complete the shortcode if the word is made up of other emojis
 3339                let mut containing_word = String::new();
 3340                for ch in snapshot
 3341                    .reversed_chars_at(position)
 3342                    .skip(chars.len() + 1)
 3343                    .take(100)
 3344                {
 3345                    if ch.is_whitespace() {
 3346                        break;
 3347                    }
 3348                    containing_word.push(ch);
 3349                }
 3350                let containing_word = containing_word.chars().rev().collect::<String>();
 3351                if util::word_consists_of_emojis(containing_word.as_str()) {
 3352                    chars.reverse();
 3353                    return Some(chars.iter().collect());
 3354                }
 3355            }
 3356
 3357            if char.is_whitespace() || !char.is_ascii() {
 3358                return None;
 3359            }
 3360            if char == ':' {
 3361                found_colon = true;
 3362            } else {
 3363                chars.push(char);
 3364            }
 3365        }
 3366        // Found a possible emoji shortcode at the beginning of the buffer
 3367        chars.reverse();
 3368        Some(chars.iter().collect())
 3369    }
 3370
 3371    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 3372        self.transact(cx, |this, cx| {
 3373            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3374                let selections = this.selections.all::<usize>(cx);
 3375                let multi_buffer = this.buffer.read(cx);
 3376                let buffer = multi_buffer.snapshot(cx);
 3377                selections
 3378                    .iter()
 3379                    .map(|selection| {
 3380                        let start_point = selection.start.to_point(&buffer);
 3381                        let mut indent =
 3382                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3383                        indent.len = cmp::min(indent.len, start_point.column);
 3384                        let start = selection.start;
 3385                        let end = selection.end;
 3386                        let selection_is_empty = start == end;
 3387                        let language_scope = buffer.language_scope_at(start);
 3388                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3389                            &language_scope
 3390                        {
 3391                            let leading_whitespace_len = buffer
 3392                                .reversed_chars_at(start)
 3393                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3394                                .map(|c| c.len_utf8())
 3395                                .sum::<usize>();
 3396
 3397                            let trailing_whitespace_len = buffer
 3398                                .chars_at(end)
 3399                                .take_while(|c| c.is_whitespace() && *c != '\n')
 3400                                .map(|c| c.len_utf8())
 3401                                .sum::<usize>();
 3402
 3403                            let insert_extra_newline =
 3404                                language.brackets().any(|(pair, enabled)| {
 3405                                    let pair_start = pair.start.trim_end();
 3406                                    let pair_end = pair.end.trim_start();
 3407
 3408                                    enabled
 3409                                        && pair.newline
 3410                                        && buffer.contains_str_at(
 3411                                            end + trailing_whitespace_len,
 3412                                            pair_end,
 3413                                        )
 3414                                        && buffer.contains_str_at(
 3415                                            (start - leading_whitespace_len)
 3416                                                .saturating_sub(pair_start.len()),
 3417                                            pair_start,
 3418                                        )
 3419                                });
 3420
 3421                            // Comment extension on newline is allowed only for cursor selections
 3422                            let comment_delimiter = maybe!({
 3423                                if !selection_is_empty {
 3424                                    return None;
 3425                                }
 3426
 3427                                if !multi_buffer.settings_at(0, cx).extend_comment_on_newline {
 3428                                    return None;
 3429                                }
 3430
 3431                                let delimiters = language.line_comment_prefixes();
 3432                                let max_len_of_delimiter =
 3433                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3434                                let (snapshot, range) =
 3435                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3436
 3437                                let mut index_of_first_non_whitespace = 0;
 3438                                let comment_candidate = snapshot
 3439                                    .chars_for_range(range)
 3440                                    .skip_while(|c| {
 3441                                        let should_skip = c.is_whitespace();
 3442                                        if should_skip {
 3443                                            index_of_first_non_whitespace += 1;
 3444                                        }
 3445                                        should_skip
 3446                                    })
 3447                                    .take(max_len_of_delimiter)
 3448                                    .collect::<String>();
 3449                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3450                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3451                                })?;
 3452                                let cursor_is_placed_after_comment_marker =
 3453                                    index_of_first_non_whitespace + comment_prefix.len()
 3454                                        <= start_point.column as usize;
 3455                                if cursor_is_placed_after_comment_marker {
 3456                                    Some(comment_prefix.clone())
 3457                                } else {
 3458                                    None
 3459                                }
 3460                            });
 3461                            (comment_delimiter, insert_extra_newline)
 3462                        } else {
 3463                            (None, false)
 3464                        };
 3465
 3466                        let capacity_for_delimiter = comment_delimiter
 3467                            .as_deref()
 3468                            .map(str::len)
 3469                            .unwrap_or_default();
 3470                        let mut new_text =
 3471                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3472                        new_text.push_str("\n");
 3473                        new_text.extend(indent.chars());
 3474                        if let Some(delimiter) = &comment_delimiter {
 3475                            new_text.push_str(&delimiter);
 3476                        }
 3477                        if insert_extra_newline {
 3478                            new_text = new_text.repeat(2);
 3479                        }
 3480
 3481                        let anchor = buffer.anchor_after(end);
 3482                        let new_selection = selection.map(|_| anchor);
 3483                        (
 3484                            (start..end, new_text),
 3485                            (insert_extra_newline, new_selection),
 3486                        )
 3487                    })
 3488                    .unzip()
 3489            };
 3490
 3491            this.edit_with_autoindent(edits, cx);
 3492            let buffer = this.buffer.read(cx).snapshot(cx);
 3493            let new_selections = selection_fixup_info
 3494                .into_iter()
 3495                .map(|(extra_newline_inserted, new_selection)| {
 3496                    let mut cursor = new_selection.end.to_point(&buffer);
 3497                    if extra_newline_inserted {
 3498                        cursor.row -= 1;
 3499                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3500                    }
 3501                    new_selection.map(|_| cursor)
 3502                })
 3503                .collect();
 3504
 3505            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 3506            this.refresh_inline_completion(true, cx);
 3507        });
 3508    }
 3509
 3510    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
 3511        let buffer = self.buffer.read(cx);
 3512        let snapshot = buffer.snapshot(cx);
 3513
 3514        let mut edits = Vec::new();
 3515        let mut rows = Vec::new();
 3516
 3517        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3518            let cursor = selection.head();
 3519            let row = cursor.row;
 3520
 3521            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3522
 3523            let newline = "\n".to_string();
 3524            edits.push((start_of_line..start_of_line, newline));
 3525
 3526            rows.push(row + rows_inserted as u32);
 3527        }
 3528
 3529        self.transact(cx, |editor, cx| {
 3530            editor.edit(edits, cx);
 3531
 3532            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3533                let mut index = 0;
 3534                s.move_cursors_with(|map, _, _| {
 3535                    let row = rows[index];
 3536                    index += 1;
 3537
 3538                    let point = Point::new(row, 0);
 3539                    let boundary = map.next_line_boundary(point).1;
 3540                    let clipped = map.clip_point(boundary, Bias::Left);
 3541
 3542                    (clipped, SelectionGoal::None)
 3543                });
 3544            });
 3545
 3546            let mut indent_edits = Vec::new();
 3547            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3548            for row in rows {
 3549                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3550                for (row, indent) in indents {
 3551                    if indent.len == 0 {
 3552                        continue;
 3553                    }
 3554
 3555                    let text = match indent.kind {
 3556                        IndentKind::Space => " ".repeat(indent.len as usize),
 3557                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3558                    };
 3559                    let point = Point::new(row.0, 0);
 3560                    indent_edits.push((point..point, text));
 3561                }
 3562            }
 3563            editor.edit(indent_edits, cx);
 3564        });
 3565    }
 3566
 3567    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
 3568        let buffer = self.buffer.read(cx);
 3569        let snapshot = buffer.snapshot(cx);
 3570
 3571        let mut edits = Vec::new();
 3572        let mut rows = Vec::new();
 3573        let mut rows_inserted = 0;
 3574
 3575        for selection in self.selections.all_adjusted(cx) {
 3576            let cursor = selection.head();
 3577            let row = cursor.row;
 3578
 3579            let point = Point::new(row + 1, 0);
 3580            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3581
 3582            let newline = "\n".to_string();
 3583            edits.push((start_of_line..start_of_line, newline));
 3584
 3585            rows_inserted += 1;
 3586            rows.push(row + rows_inserted);
 3587        }
 3588
 3589        self.transact(cx, |editor, cx| {
 3590            editor.edit(edits, cx);
 3591
 3592            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3593                let mut index = 0;
 3594                s.move_cursors_with(|map, _, _| {
 3595                    let row = rows[index];
 3596                    index += 1;
 3597
 3598                    let point = Point::new(row, 0);
 3599                    let boundary = map.next_line_boundary(point).1;
 3600                    let clipped = map.clip_point(boundary, Bias::Left);
 3601
 3602                    (clipped, SelectionGoal::None)
 3603                });
 3604            });
 3605
 3606            let mut indent_edits = Vec::new();
 3607            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3608            for row in rows {
 3609                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3610                for (row, indent) in indents {
 3611                    if indent.len == 0 {
 3612                        continue;
 3613                    }
 3614
 3615                    let text = match indent.kind {
 3616                        IndentKind::Space => " ".repeat(indent.len as usize),
 3617                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3618                    };
 3619                    let point = Point::new(row.0, 0);
 3620                    indent_edits.push((point..point, text));
 3621                }
 3622            }
 3623            editor.edit(indent_edits, cx);
 3624        });
 3625    }
 3626
 3627    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 3628        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3629            original_indent_columns: Vec::new(),
 3630        });
 3631        self.insert_with_autoindent_mode(text, autoindent, cx);
 3632    }
 3633
 3634    fn insert_with_autoindent_mode(
 3635        &mut self,
 3636        text: &str,
 3637        autoindent_mode: Option<AutoindentMode>,
 3638        cx: &mut ViewContext<Self>,
 3639    ) {
 3640        if self.read_only(cx) {
 3641            return;
 3642        }
 3643
 3644        let text: Arc<str> = text.into();
 3645        self.transact(cx, |this, cx| {
 3646            let old_selections = this.selections.all_adjusted(cx);
 3647            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3648                let anchors = {
 3649                    let snapshot = buffer.read(cx);
 3650                    old_selections
 3651                        .iter()
 3652                        .map(|s| {
 3653                            let anchor = snapshot.anchor_after(s.head());
 3654                            s.map(|_| anchor)
 3655                        })
 3656                        .collect::<Vec<_>>()
 3657                };
 3658                buffer.edit(
 3659                    old_selections
 3660                        .iter()
 3661                        .map(|s| (s.start..s.end, text.clone())),
 3662                    autoindent_mode,
 3663                    cx,
 3664                );
 3665                anchors
 3666            });
 3667
 3668            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 3669                s.select_anchors(selection_anchors);
 3670            })
 3671        });
 3672    }
 3673
 3674    fn trigger_completion_on_input(
 3675        &mut self,
 3676        text: &str,
 3677        trigger_in_words: bool,
 3678        cx: &mut ViewContext<Self>,
 3679    ) {
 3680        if self.is_completion_trigger(text, trigger_in_words, cx) {
 3681            self.show_completions(
 3682                &ShowCompletions {
 3683                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 3684                },
 3685                cx,
 3686            );
 3687        } else {
 3688            self.hide_context_menu(cx);
 3689        }
 3690    }
 3691
 3692    fn is_completion_trigger(
 3693        &self,
 3694        text: &str,
 3695        trigger_in_words: bool,
 3696        cx: &mut ViewContext<Self>,
 3697    ) -> bool {
 3698        let position = self.selections.newest_anchor().head();
 3699        let multibuffer = self.buffer.read(cx);
 3700        let Some(buffer) = position
 3701            .buffer_id
 3702            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 3703        else {
 3704            return false;
 3705        };
 3706
 3707        if let Some(completion_provider) = &self.completion_provider {
 3708            completion_provider.is_completion_trigger(
 3709                &buffer,
 3710                position.text_anchor,
 3711                text,
 3712                trigger_in_words,
 3713                cx,
 3714            )
 3715        } else {
 3716            false
 3717        }
 3718    }
 3719
 3720    /// If any empty selections is touching the start of its innermost containing autoclose
 3721    /// region, expand it to select the brackets.
 3722    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
 3723        let selections = self.selections.all::<usize>(cx);
 3724        let buffer = self.buffer.read(cx).read(cx);
 3725        let new_selections = self
 3726            .selections_with_autoclose_regions(selections, &buffer)
 3727            .map(|(mut selection, region)| {
 3728                if !selection.is_empty() {
 3729                    return selection;
 3730                }
 3731
 3732                if let Some(region) = region {
 3733                    let mut range = region.range.to_offset(&buffer);
 3734                    if selection.start == range.start && range.start >= region.pair.start.len() {
 3735                        range.start -= region.pair.start.len();
 3736                        if buffer.contains_str_at(range.start, &region.pair.start)
 3737                            && buffer.contains_str_at(range.end, &region.pair.end)
 3738                        {
 3739                            range.end += region.pair.end.len();
 3740                            selection.start = range.start;
 3741                            selection.end = range.end;
 3742
 3743                            return selection;
 3744                        }
 3745                    }
 3746                }
 3747
 3748                let always_treat_brackets_as_autoclosed = buffer
 3749                    .settings_at(selection.start, cx)
 3750                    .always_treat_brackets_as_autoclosed;
 3751
 3752                if !always_treat_brackets_as_autoclosed {
 3753                    return selection;
 3754                }
 3755
 3756                if let Some(scope) = buffer.language_scope_at(selection.start) {
 3757                    for (pair, enabled) in scope.brackets() {
 3758                        if !enabled || !pair.close {
 3759                            continue;
 3760                        }
 3761
 3762                        if buffer.contains_str_at(selection.start, &pair.end) {
 3763                            let pair_start_len = pair.start.len();
 3764                            if buffer.contains_str_at(selection.start - pair_start_len, &pair.start)
 3765                            {
 3766                                selection.start -= pair_start_len;
 3767                                selection.end += pair.end.len();
 3768
 3769                                return selection;
 3770                            }
 3771                        }
 3772                    }
 3773                }
 3774
 3775                selection
 3776            })
 3777            .collect();
 3778
 3779        drop(buffer);
 3780        self.change_selections(None, cx, |selections| selections.select(new_selections));
 3781    }
 3782
 3783    /// Iterate the given selections, and for each one, find the smallest surrounding
 3784    /// autoclose region. This uses the ordering of the selections and the autoclose
 3785    /// regions to avoid repeated comparisons.
 3786    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 3787        &'a self,
 3788        selections: impl IntoIterator<Item = Selection<D>>,
 3789        buffer: &'a MultiBufferSnapshot,
 3790    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 3791        let mut i = 0;
 3792        let mut regions = self.autoclose_regions.as_slice();
 3793        selections.into_iter().map(move |selection| {
 3794            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 3795
 3796            let mut enclosing = None;
 3797            while let Some(pair_state) = regions.get(i) {
 3798                if pair_state.range.end.to_offset(buffer) < range.start {
 3799                    regions = &regions[i + 1..];
 3800                    i = 0;
 3801                } else if pair_state.range.start.to_offset(buffer) > range.end {
 3802                    break;
 3803                } else {
 3804                    if pair_state.selection_id == selection.id {
 3805                        enclosing = Some(pair_state);
 3806                    }
 3807                    i += 1;
 3808                }
 3809            }
 3810
 3811            (selection.clone(), enclosing)
 3812        })
 3813    }
 3814
 3815    /// Remove any autoclose regions that no longer contain their selection.
 3816    fn invalidate_autoclose_regions(
 3817        &mut self,
 3818        mut selections: &[Selection<Anchor>],
 3819        buffer: &MultiBufferSnapshot,
 3820    ) {
 3821        self.autoclose_regions.retain(|state| {
 3822            let mut i = 0;
 3823            while let Some(selection) = selections.get(i) {
 3824                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 3825                    selections = &selections[1..];
 3826                    continue;
 3827                }
 3828                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 3829                    break;
 3830                }
 3831                if selection.id == state.selection_id {
 3832                    return true;
 3833                } else {
 3834                    i += 1;
 3835                }
 3836            }
 3837            false
 3838        });
 3839    }
 3840
 3841    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 3842        let offset = position.to_offset(buffer);
 3843        let (word_range, kind) = buffer.surrounding_word(offset);
 3844        if offset > word_range.start && kind == Some(CharKind::Word) {
 3845            Some(
 3846                buffer
 3847                    .text_for_range(word_range.start..offset)
 3848                    .collect::<String>(),
 3849            )
 3850        } else {
 3851            None
 3852        }
 3853    }
 3854
 3855    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
 3856        self.refresh_inlay_hints(
 3857            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
 3858            cx,
 3859        );
 3860    }
 3861
 3862    pub fn inlay_hints_enabled(&self) -> bool {
 3863        self.inlay_hint_cache.enabled
 3864    }
 3865
 3866    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
 3867        if self.project.is_none() || self.mode != EditorMode::Full {
 3868            return;
 3869        }
 3870
 3871        let reason_description = reason.description();
 3872        let ignore_debounce = matches!(
 3873            reason,
 3874            InlayHintRefreshReason::SettingsChange(_)
 3875                | InlayHintRefreshReason::Toggle(_)
 3876                | InlayHintRefreshReason::ExcerptsRemoved(_)
 3877        );
 3878        let (invalidate_cache, required_languages) = match reason {
 3879            InlayHintRefreshReason::Toggle(enabled) => {
 3880                self.inlay_hint_cache.enabled = enabled;
 3881                if enabled {
 3882                    (InvalidationStrategy::RefreshRequested, None)
 3883                } else {
 3884                    self.inlay_hint_cache.clear();
 3885                    self.splice_inlays(
 3886                        self.visible_inlay_hints(cx)
 3887                            .iter()
 3888                            .map(|inlay| inlay.id)
 3889                            .collect(),
 3890                        Vec::new(),
 3891                        cx,
 3892                    );
 3893                    return;
 3894                }
 3895            }
 3896            InlayHintRefreshReason::SettingsChange(new_settings) => {
 3897                match self.inlay_hint_cache.update_settings(
 3898                    &self.buffer,
 3899                    new_settings,
 3900                    self.visible_inlay_hints(cx),
 3901                    cx,
 3902                ) {
 3903                    ControlFlow::Break(Some(InlaySplice {
 3904                        to_remove,
 3905                        to_insert,
 3906                    })) => {
 3907                        self.splice_inlays(to_remove, to_insert, cx);
 3908                        return;
 3909                    }
 3910                    ControlFlow::Break(None) => return,
 3911                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 3912                }
 3913            }
 3914            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 3915                if let Some(InlaySplice {
 3916                    to_remove,
 3917                    to_insert,
 3918                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 3919                {
 3920                    self.splice_inlays(to_remove, to_insert, cx);
 3921                }
 3922                return;
 3923            }
 3924            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 3925            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 3926                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 3927            }
 3928            InlayHintRefreshReason::RefreshRequested => {
 3929                (InvalidationStrategy::RefreshRequested, None)
 3930            }
 3931        };
 3932
 3933        if let Some(InlaySplice {
 3934            to_remove,
 3935            to_insert,
 3936        }) = self.inlay_hint_cache.spawn_hint_refresh(
 3937            reason_description,
 3938            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 3939            invalidate_cache,
 3940            ignore_debounce,
 3941            cx,
 3942        ) {
 3943            self.splice_inlays(to_remove, to_insert, cx);
 3944        }
 3945    }
 3946
 3947    fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
 3948        self.display_map
 3949            .read(cx)
 3950            .current_inlays()
 3951            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 3952            .cloned()
 3953            .collect()
 3954    }
 3955
 3956    pub fn excerpts_for_inlay_hints_query(
 3957        &self,
 3958        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 3959        cx: &mut ViewContext<Editor>,
 3960    ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
 3961        let Some(project) = self.project.as_ref() else {
 3962            return HashMap::default();
 3963        };
 3964        let project = project.read(cx);
 3965        let multi_buffer = self.buffer().read(cx);
 3966        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 3967        let multi_buffer_visible_start = self
 3968            .scroll_manager
 3969            .anchor()
 3970            .anchor
 3971            .to_point(&multi_buffer_snapshot);
 3972        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 3973            multi_buffer_visible_start
 3974                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 3975            Bias::Left,
 3976        );
 3977        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 3978        multi_buffer
 3979            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
 3980            .into_iter()
 3981            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 3982            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
 3983                let buffer = buffer_handle.read(cx);
 3984                let buffer_file = project::File::from_dyn(buffer.file())?;
 3985                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 3986                let worktree_entry = buffer_worktree
 3987                    .read(cx)
 3988                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 3989                if worktree_entry.is_ignored {
 3990                    return None;
 3991                }
 3992
 3993                let language = buffer.language()?;
 3994                if let Some(restrict_to_languages) = restrict_to_languages {
 3995                    if !restrict_to_languages.contains(language) {
 3996                        return None;
 3997                    }
 3998                }
 3999                Some((
 4000                    excerpt_id,
 4001                    (
 4002                        buffer_handle,
 4003                        buffer.version().clone(),
 4004                        excerpt_visible_range,
 4005                    ),
 4006                ))
 4007            })
 4008            .collect()
 4009    }
 4010
 4011    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
 4012        TextLayoutDetails {
 4013            text_system: cx.text_system().clone(),
 4014            editor_style: self.style.clone().unwrap(),
 4015            rem_size: cx.rem_size(),
 4016            scroll_anchor: self.scroll_manager.anchor(),
 4017            visible_rows: self.visible_line_count(),
 4018            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4019        }
 4020    }
 4021
 4022    fn splice_inlays(
 4023        &self,
 4024        to_remove: Vec<InlayId>,
 4025        to_insert: Vec<Inlay>,
 4026        cx: &mut ViewContext<Self>,
 4027    ) {
 4028        self.display_map.update(cx, |display_map, cx| {
 4029            display_map.splice_inlays(to_remove, to_insert, cx);
 4030        });
 4031        cx.notify();
 4032    }
 4033
 4034    fn trigger_on_type_formatting(
 4035        &self,
 4036        input: String,
 4037        cx: &mut ViewContext<Self>,
 4038    ) -> Option<Task<Result<()>>> {
 4039        if input.len() != 1 {
 4040            return None;
 4041        }
 4042
 4043        let project = self.project.as_ref()?;
 4044        let position = self.selections.newest_anchor().head();
 4045        let (buffer, buffer_position) = self
 4046            .buffer
 4047            .read(cx)
 4048            .text_anchor_for_position(position, cx)?;
 4049
 4050        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4051        // hence we do LSP request & edit on host side only — add formats to host's history.
 4052        let push_to_lsp_host_history = true;
 4053        // If this is not the host, append its history with new edits.
 4054        let push_to_client_history = project.read(cx).is_remote();
 4055
 4056        let on_type_formatting = project.update(cx, |project, cx| {
 4057            project.on_type_format(
 4058                buffer.clone(),
 4059                buffer_position,
 4060                input,
 4061                push_to_lsp_host_history,
 4062                cx,
 4063            )
 4064        });
 4065        Some(cx.spawn(|editor, mut cx| async move {
 4066            if let Some(transaction) = on_type_formatting.await? {
 4067                if push_to_client_history {
 4068                    buffer
 4069                        .update(&mut cx, |buffer, _| {
 4070                            buffer.push_transaction(transaction, Instant::now());
 4071                        })
 4072                        .ok();
 4073                }
 4074                editor.update(&mut cx, |editor, cx| {
 4075                    editor.refresh_document_highlights(cx);
 4076                })?;
 4077            }
 4078            Ok(())
 4079        }))
 4080    }
 4081
 4082    pub fn show_completions(&mut self, options: &ShowCompletions, cx: &mut ViewContext<Self>) {
 4083        if self.pending_rename.is_some() {
 4084            return;
 4085        }
 4086
 4087        let Some(provider) = self.completion_provider.as_ref() else {
 4088            return;
 4089        };
 4090
 4091        let position = self.selections.newest_anchor().head();
 4092        let (buffer, buffer_position) =
 4093            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4094                output
 4095            } else {
 4096                return;
 4097            };
 4098
 4099        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4100        let is_followup_invoke = {
 4101            let context_menu_state = self.context_menu.read();
 4102            matches!(
 4103                context_menu_state.deref(),
 4104                Some(ContextMenu::Completions(_))
 4105            )
 4106        };
 4107        let trigger_kind = match (&options.trigger, is_followup_invoke) {
 4108            (_, true) => CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS,
 4109            (Some(trigger), _) if buffer.read(cx).completion_triggers().contains(&trigger) => {
 4110                CompletionTriggerKind::TRIGGER_CHARACTER
 4111            }
 4112
 4113            _ => CompletionTriggerKind::INVOKED,
 4114        };
 4115        let completion_context = CompletionContext {
 4116            trigger_character: options.trigger.as_ref().and_then(|trigger| {
 4117                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4118                    Some(String::from(trigger))
 4119                } else {
 4120                    None
 4121                }
 4122            }),
 4123            trigger_kind,
 4124        };
 4125        let completions = provider.completions(&buffer, buffer_position, completion_context, cx);
 4126        let sort_completions = provider.sort_completions();
 4127
 4128        let id = post_inc(&mut self.next_completion_id);
 4129        let task = cx.spawn(|this, mut cx| {
 4130            async move {
 4131                this.update(&mut cx, |this, _| {
 4132                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4133                })?;
 4134                let completions = completions.await.log_err();
 4135                let menu = if let Some(completions) = completions {
 4136                    let mut menu = CompletionsMenu {
 4137                        id,
 4138                        sort_completions,
 4139                        initial_position: position,
 4140                        match_candidates: completions
 4141                            .iter()
 4142                            .enumerate()
 4143                            .map(|(id, completion)| {
 4144                                StringMatchCandidate::new(
 4145                                    id,
 4146                                    completion.label.text[completion.label.filter_range.clone()]
 4147                                        .into(),
 4148                                )
 4149                            })
 4150                            .collect(),
 4151                        buffer: buffer.clone(),
 4152                        completions: Arc::new(RwLock::new(completions.into())),
 4153                        matches: Vec::new().into(),
 4154                        selected_item: 0,
 4155                        scroll_handle: UniformListScrollHandle::new(),
 4156                        selected_completion_documentation_resolve_debounce: Arc::new(Mutex::new(
 4157                            DebouncedDelay::new(),
 4158                        )),
 4159                    };
 4160                    menu.filter(query.as_deref(), cx.background_executor().clone())
 4161                        .await;
 4162
 4163                    if menu.matches.is_empty() {
 4164                        None
 4165                    } else {
 4166                        this.update(&mut cx, |editor, cx| {
 4167                            let completions = menu.completions.clone();
 4168                            let matches = menu.matches.clone();
 4169
 4170                            let delay_ms = EditorSettings::get_global(cx)
 4171                                .completion_documentation_secondary_query_debounce;
 4172                            let delay = Duration::from_millis(delay_ms);
 4173                            editor
 4174                                .completion_documentation_pre_resolve_debounce
 4175                                .fire_new(delay, cx, |editor, cx| {
 4176                                    CompletionsMenu::pre_resolve_completion_documentation(
 4177                                        buffer,
 4178                                        completions,
 4179                                        matches,
 4180                                        editor,
 4181                                        cx,
 4182                                    )
 4183                                });
 4184                        })
 4185                        .ok();
 4186                        Some(menu)
 4187                    }
 4188                } else {
 4189                    None
 4190                };
 4191
 4192                this.update(&mut cx, |this, cx| {
 4193                    let mut context_menu = this.context_menu.write();
 4194                    match context_menu.as_ref() {
 4195                        None => {}
 4196
 4197                        Some(ContextMenu::Completions(prev_menu)) => {
 4198                            if prev_menu.id > id {
 4199                                return;
 4200                            }
 4201                        }
 4202
 4203                        _ => return,
 4204                    }
 4205
 4206                    if this.focus_handle.is_focused(cx) && menu.is_some() {
 4207                        let menu = menu.unwrap();
 4208                        *context_menu = Some(ContextMenu::Completions(menu));
 4209                        drop(context_menu);
 4210                        this.discard_inline_completion(false, cx);
 4211                        cx.notify();
 4212                    } else if this.completion_tasks.len() <= 1 {
 4213                        // If there are no more completion tasks and the last menu was
 4214                        // empty, we should hide it. If it was already hidden, we should
 4215                        // also show the copilot completion when available.
 4216                        drop(context_menu);
 4217                        if this.hide_context_menu(cx).is_none() {
 4218                            this.update_visible_inline_completion(cx);
 4219                        }
 4220                    }
 4221                })?;
 4222
 4223                Ok::<_, anyhow::Error>(())
 4224            }
 4225            .log_err()
 4226        });
 4227
 4228        self.completion_tasks.push((id, task));
 4229    }
 4230
 4231    pub fn confirm_completion(
 4232        &mut self,
 4233        action: &ConfirmCompletion,
 4234        cx: &mut ViewContext<Self>,
 4235    ) -> Option<Task<Result<()>>> {
 4236        self.do_completion(action.item_ix, CompletionIntent::Complete, cx)
 4237    }
 4238
 4239    pub fn compose_completion(
 4240        &mut self,
 4241        action: &ComposeCompletion,
 4242        cx: &mut ViewContext<Self>,
 4243    ) -> Option<Task<Result<()>>> {
 4244        self.do_completion(action.item_ix, CompletionIntent::Compose, cx)
 4245    }
 4246
 4247    fn do_completion(
 4248        &mut self,
 4249        item_ix: Option<usize>,
 4250        intent: CompletionIntent,
 4251        cx: &mut ViewContext<Editor>,
 4252    ) -> Option<Task<std::result::Result<(), anyhow::Error>>> {
 4253        use language::ToOffset as _;
 4254
 4255        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
 4256            menu
 4257        } else {
 4258            return None;
 4259        };
 4260
 4261        let mat = completions_menu
 4262            .matches
 4263            .get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4264        let buffer_handle = completions_menu.buffer;
 4265        let completions = completions_menu.completions.read();
 4266        let completion = completions.get(mat.candidate_id)?;
 4267        cx.stop_propagation();
 4268
 4269        let snippet;
 4270        let text;
 4271
 4272        if completion.is_snippet() {
 4273            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4274            text = snippet.as_ref().unwrap().text.clone();
 4275        } else {
 4276            snippet = None;
 4277            text = completion.new_text.clone();
 4278        };
 4279        let selections = self.selections.all::<usize>(cx);
 4280        let buffer = buffer_handle.read(cx);
 4281        let old_range = completion.old_range.to_offset(buffer);
 4282        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 4283
 4284        let newest_selection = self.selections.newest_anchor();
 4285        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
 4286            return None;
 4287        }
 4288
 4289        let lookbehind = newest_selection
 4290            .start
 4291            .text_anchor
 4292            .to_offset(buffer)
 4293            .saturating_sub(old_range.start);
 4294        let lookahead = old_range
 4295            .end
 4296            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 4297        let mut common_prefix_len = old_text
 4298            .bytes()
 4299            .zip(text.bytes())
 4300            .take_while(|(a, b)| a == b)
 4301            .count();
 4302
 4303        let snapshot = self.buffer.read(cx).snapshot(cx);
 4304        let mut range_to_replace: Option<Range<isize>> = None;
 4305        let mut ranges = Vec::new();
 4306        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4307        for selection in &selections {
 4308            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 4309                let start = selection.start.saturating_sub(lookbehind);
 4310                let end = selection.end + lookahead;
 4311                if selection.id == newest_selection.id {
 4312                    range_to_replace = Some(
 4313                        ((start + common_prefix_len) as isize - selection.start as isize)
 4314                            ..(end as isize - selection.start as isize),
 4315                    );
 4316                }
 4317                ranges.push(start + common_prefix_len..end);
 4318            } else {
 4319                common_prefix_len = 0;
 4320                ranges.clear();
 4321                ranges.extend(selections.iter().map(|s| {
 4322                    if s.id == newest_selection.id {
 4323                        range_to_replace = Some(
 4324                            old_range.start.to_offset_utf16(&snapshot).0 as isize
 4325                                - selection.start as isize
 4326                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
 4327                                    - selection.start as isize,
 4328                        );
 4329                        old_range.clone()
 4330                    } else {
 4331                        s.start..s.end
 4332                    }
 4333                }));
 4334                break;
 4335            }
 4336            if !self.linked_edit_ranges.is_empty() {
 4337                let start_anchor = snapshot.anchor_before(selection.head());
 4338                let end_anchor = snapshot.anchor_after(selection.tail());
 4339                if let Some(ranges) = self
 4340                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4341                {
 4342                    for (buffer, edits) in ranges {
 4343                        linked_edits.entry(buffer.clone()).or_default().extend(
 4344                            edits
 4345                                .into_iter()
 4346                                .map(|range| (range, text[common_prefix_len..].to_owned())),
 4347                        );
 4348                    }
 4349                }
 4350            }
 4351        }
 4352        let text = &text[common_prefix_len..];
 4353
 4354        cx.emit(EditorEvent::InputHandled {
 4355            utf16_range_to_replace: range_to_replace,
 4356            text: text.into(),
 4357        });
 4358
 4359        self.transact(cx, |this, cx| {
 4360            if let Some(mut snippet) = snippet {
 4361                snippet.text = text.to_string();
 4362                for tabstop in snippet.tabstops.iter_mut().flatten() {
 4363                    tabstop.start -= common_prefix_len as isize;
 4364                    tabstop.end -= common_prefix_len as isize;
 4365                }
 4366
 4367                this.insert_snippet(&ranges, snippet, cx).log_err();
 4368            } else {
 4369                this.buffer.update(cx, |buffer, cx| {
 4370                    buffer.edit(
 4371                        ranges.iter().map(|range| (range.clone(), text)),
 4372                        this.autoindent_mode.clone(),
 4373                        cx,
 4374                    );
 4375                });
 4376            }
 4377            for (buffer, edits) in linked_edits {
 4378                buffer.update(cx, |buffer, cx| {
 4379                    let snapshot = buffer.snapshot();
 4380                    let edits = edits
 4381                        .into_iter()
 4382                        .map(|(range, text)| {
 4383                            use text::ToPoint as TP;
 4384                            let end_point = TP::to_point(&range.end, &snapshot);
 4385                            let start_point = TP::to_point(&range.start, &snapshot);
 4386                            (start_point..end_point, text)
 4387                        })
 4388                        .sorted_by_key(|(range, _)| range.start)
 4389                        .collect::<Vec<_>>();
 4390                    buffer.edit(edits, None, cx);
 4391                })
 4392            }
 4393
 4394            this.refresh_inline_completion(true, cx);
 4395        });
 4396
 4397        let show_new_completions_on_confirm = completion
 4398            .confirm
 4399            .as_ref()
 4400            .map_or(false, |confirm| confirm(intent, cx));
 4401        if show_new_completions_on_confirm {
 4402            self.show_completions(&ShowCompletions { trigger: None }, cx);
 4403        }
 4404
 4405        let provider = self.completion_provider.as_ref()?;
 4406        let apply_edits = provider.apply_additional_edits_for_completion(
 4407            buffer_handle,
 4408            completion.clone(),
 4409            true,
 4410            cx,
 4411        );
 4412
 4413        let editor_settings = EditorSettings::get_global(cx);
 4414        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 4415            // After the code completion is finished, users often want to know what signatures are needed.
 4416            // so we should automatically call signature_help
 4417            self.show_signature_help(&ShowSignatureHelp, cx);
 4418        }
 4419
 4420        Some(cx.foreground_executor().spawn(async move {
 4421            apply_edits.await?;
 4422            Ok(())
 4423        }))
 4424    }
 4425
 4426    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
 4427        let mut context_menu = self.context_menu.write();
 4428        if let Some(ContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 4429            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 4430                // Toggle if we're selecting the same one
 4431                *context_menu = None;
 4432                cx.notify();
 4433                return;
 4434            } else {
 4435                // Otherwise, clear it and start a new one
 4436                *context_menu = None;
 4437                cx.notify();
 4438            }
 4439        }
 4440        drop(context_menu);
 4441        let snapshot = self.snapshot(cx);
 4442        let deployed_from_indicator = action.deployed_from_indicator;
 4443        let mut task = self.code_actions_task.take();
 4444        let action = action.clone();
 4445        cx.spawn(|editor, mut cx| async move {
 4446            while let Some(prev_task) = task {
 4447                prev_task.await;
 4448                task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?;
 4449            }
 4450
 4451            let spawned_test_task = editor.update(&mut cx, |editor, cx| {
 4452                if editor.focus_handle.is_focused(cx) {
 4453                    let multibuffer_point = action
 4454                        .deployed_from_indicator
 4455                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4456                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 4457                    let (buffer, buffer_row) = snapshot
 4458                        .buffer_snapshot
 4459                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4460                        .and_then(|(buffer_snapshot, range)| {
 4461                            editor
 4462                                .buffer
 4463                                .read(cx)
 4464                                .buffer(buffer_snapshot.remote_id())
 4465                                .map(|buffer| (buffer, range.start.row))
 4466                        })?;
 4467                    let (_, code_actions) = editor
 4468                        .available_code_actions
 4469                        .clone()
 4470                        .and_then(|(location, code_actions)| {
 4471                            let snapshot = location.buffer.read(cx).snapshot();
 4472                            let point_range = location.range.to_point(&snapshot);
 4473                            let point_range = point_range.start.row..=point_range.end.row;
 4474                            if point_range.contains(&buffer_row) {
 4475                                Some((location, code_actions))
 4476                            } else {
 4477                                None
 4478                            }
 4479                        })
 4480                        .unzip();
 4481                    let buffer_id = buffer.read(cx).remote_id();
 4482                    let tasks = editor
 4483                        .tasks
 4484                        .get(&(buffer_id, buffer_row))
 4485                        .map(|t| Arc::new(t.to_owned()));
 4486                    if tasks.is_none() && code_actions.is_none() {
 4487                        return None;
 4488                    }
 4489
 4490                    editor.completion_tasks.clear();
 4491                    editor.discard_inline_completion(false, cx);
 4492                    let task_context =
 4493                        tasks
 4494                            .as_ref()
 4495                            .zip(editor.project.clone())
 4496                            .map(|(tasks, project)| {
 4497                                let position = Point::new(buffer_row, tasks.column);
 4498                                let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 4499                                let location = Location {
 4500                                    buffer: buffer.clone(),
 4501                                    range: range_start..range_start,
 4502                                };
 4503                                // Fill in the environmental variables from the tree-sitter captures
 4504                                let mut captured_task_variables = TaskVariables::default();
 4505                                for (capture_name, value) in tasks.extra_variables.clone() {
 4506                                    captured_task_variables.insert(
 4507                                        task::VariableName::Custom(capture_name.into()),
 4508                                        value.clone(),
 4509                                    );
 4510                                }
 4511                                project.update(cx, |project, cx| {
 4512                                    project.task_context_for_location(
 4513                                        captured_task_variables,
 4514                                        location,
 4515                                        cx,
 4516                                    )
 4517                                })
 4518                            });
 4519
 4520                    Some(cx.spawn(|editor, mut cx| async move {
 4521                        let task_context = match task_context {
 4522                            Some(task_context) => task_context.await,
 4523                            None => None,
 4524                        };
 4525                        let resolved_tasks =
 4526                            tasks.zip(task_context).map(|(tasks, task_context)| {
 4527                                Arc::new(ResolvedTasks {
 4528                                    templates: tasks
 4529                                        .templates
 4530                                        .iter()
 4531                                        .filter_map(|(kind, template)| {
 4532                                            template
 4533                                                .resolve_task(&kind.to_id_base(), &task_context)
 4534                                                .map(|task| (kind.clone(), task))
 4535                                        })
 4536                                        .collect(),
 4537                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 4538                                        multibuffer_point.row,
 4539                                        tasks.column,
 4540                                    )),
 4541                                })
 4542                            });
 4543                        let spawn_straight_away = resolved_tasks
 4544                            .as_ref()
 4545                            .map_or(false, |tasks| tasks.templates.len() == 1)
 4546                            && code_actions
 4547                                .as_ref()
 4548                                .map_or(true, |actions| actions.is_empty());
 4549                        if let Some(task) = editor
 4550                            .update(&mut cx, |editor, cx| {
 4551                                *editor.context_menu.write() =
 4552                                    Some(ContextMenu::CodeActions(CodeActionsMenu {
 4553                                        buffer,
 4554                                        actions: CodeActionContents {
 4555                                            tasks: resolved_tasks,
 4556                                            actions: code_actions,
 4557                                        },
 4558                                        selected_item: Default::default(),
 4559                                        scroll_handle: UniformListScrollHandle::default(),
 4560                                        deployed_from_indicator,
 4561                                    }));
 4562                                if spawn_straight_away {
 4563                                    if let Some(task) = editor.confirm_code_action(
 4564                                        &ConfirmCodeAction { item_ix: Some(0) },
 4565                                        cx,
 4566                                    ) {
 4567                                        cx.notify();
 4568                                        return task;
 4569                                    }
 4570                                }
 4571                                cx.notify();
 4572                                Task::ready(Ok(()))
 4573                            })
 4574                            .ok()
 4575                        {
 4576                            task.await
 4577                        } else {
 4578                            Ok(())
 4579                        }
 4580                    }))
 4581                } else {
 4582                    Some(Task::ready(Ok(())))
 4583                }
 4584            })?;
 4585            if let Some(task) = spawned_test_task {
 4586                task.await?;
 4587            }
 4588
 4589            Ok::<_, anyhow::Error>(())
 4590        })
 4591        .detach_and_log_err(cx);
 4592    }
 4593
 4594    pub fn confirm_code_action(
 4595        &mut self,
 4596        action: &ConfirmCodeAction,
 4597        cx: &mut ViewContext<Self>,
 4598    ) -> Option<Task<Result<()>>> {
 4599        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
 4600            menu
 4601        } else {
 4602            return None;
 4603        };
 4604        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 4605        let action = actions_menu.actions.get(action_ix)?;
 4606        let title = action.label();
 4607        let buffer = actions_menu.buffer;
 4608        let workspace = self.workspace()?;
 4609
 4610        match action {
 4611            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 4612                workspace.update(cx, |workspace, cx| {
 4613                    workspace::tasks::schedule_resolved_task(
 4614                        workspace,
 4615                        task_source_kind,
 4616                        resolved_task,
 4617                        false,
 4618                        cx,
 4619                    );
 4620
 4621                    Some(Task::ready(Ok(())))
 4622                })
 4623            }
 4624            CodeActionsItem::CodeAction(action) => {
 4625                let apply_code_actions = workspace
 4626                    .read(cx)
 4627                    .project()
 4628                    .clone()
 4629                    .update(cx, |project, cx| {
 4630                        project.apply_code_action(buffer, action, true, cx)
 4631                    });
 4632                let workspace = workspace.downgrade();
 4633                Some(cx.spawn(|editor, cx| async move {
 4634                    let project_transaction = apply_code_actions.await?;
 4635                    Self::open_project_transaction(
 4636                        &editor,
 4637                        workspace,
 4638                        project_transaction,
 4639                        title,
 4640                        cx,
 4641                    )
 4642                    .await
 4643                }))
 4644            }
 4645        }
 4646    }
 4647
 4648    pub async fn open_project_transaction(
 4649        this: &WeakView<Editor>,
 4650        workspace: WeakView<Workspace>,
 4651        transaction: ProjectTransaction,
 4652        title: String,
 4653        mut cx: AsyncWindowContext,
 4654    ) -> Result<()> {
 4655        let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
 4656
 4657        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 4658        cx.update(|cx| {
 4659            entries.sort_unstable_by_key(|(buffer, _)| {
 4660                buffer.read(cx).file().map(|f| f.path().clone())
 4661            });
 4662        })?;
 4663
 4664        // If the project transaction's edits are all contained within this editor, then
 4665        // avoid opening a new editor to display them.
 4666
 4667        if let Some((buffer, transaction)) = entries.first() {
 4668            if entries.len() == 1 {
 4669                let excerpt = this.update(&mut cx, |editor, cx| {
 4670                    editor
 4671                        .buffer()
 4672                        .read(cx)
 4673                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 4674                })?;
 4675                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 4676                    if excerpted_buffer == *buffer {
 4677                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
 4678                            let excerpt_range = excerpt_range.to_offset(buffer);
 4679                            buffer
 4680                                .edited_ranges_for_transaction::<usize>(transaction)
 4681                                .all(|range| {
 4682                                    excerpt_range.start <= range.start
 4683                                        && excerpt_range.end >= range.end
 4684                                })
 4685                        })?;
 4686
 4687                        if all_edits_within_excerpt {
 4688                            return Ok(());
 4689                        }
 4690                    }
 4691                }
 4692            }
 4693        } else {
 4694            return Ok(());
 4695        }
 4696
 4697        let mut ranges_to_highlight = Vec::new();
 4698        let excerpt_buffer = cx.new_model(|cx| {
 4699            let mut multibuffer =
 4700                MultiBuffer::new(replica_id, Capability::ReadWrite).with_title(title);
 4701            for (buffer_handle, transaction) in &entries {
 4702                let buffer = buffer_handle.read(cx);
 4703                ranges_to_highlight.extend(
 4704                    multibuffer.push_excerpts_with_context_lines(
 4705                        buffer_handle.clone(),
 4706                        buffer
 4707                            .edited_ranges_for_transaction::<usize>(transaction)
 4708                            .collect(),
 4709                        DEFAULT_MULTIBUFFER_CONTEXT,
 4710                        cx,
 4711                    ),
 4712                );
 4713            }
 4714            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 4715            multibuffer
 4716        })?;
 4717
 4718        workspace.update(&mut cx, |workspace, cx| {
 4719            let project = workspace.project().clone();
 4720            let editor =
 4721                cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), true, cx));
 4722            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, cx);
 4723            editor.update(cx, |editor, cx| {
 4724                editor.highlight_background::<Self>(
 4725                    &ranges_to_highlight,
 4726                    |theme| theme.editor_highlighted_line_background,
 4727                    cx,
 4728                );
 4729            });
 4730        })?;
 4731
 4732        Ok(())
 4733    }
 4734
 4735    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 4736        let project = self.project.clone()?;
 4737        let buffer = self.buffer.read(cx);
 4738        let newest_selection = self.selections.newest_anchor().clone();
 4739        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 4740        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 4741        if start_buffer != end_buffer {
 4742            return None;
 4743        }
 4744
 4745        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
 4746            cx.background_executor()
 4747                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 4748                .await;
 4749
 4750            let actions = if let Ok(code_actions) = project.update(&mut cx, |project, cx| {
 4751                project.code_actions(&start_buffer, start..end, cx)
 4752            }) {
 4753                code_actions.await
 4754            } else {
 4755                Vec::new()
 4756            };
 4757
 4758            this.update(&mut cx, |this, cx| {
 4759                this.available_code_actions = if actions.is_empty() {
 4760                    None
 4761                } else {
 4762                    Some((
 4763                        Location {
 4764                            buffer: start_buffer,
 4765                            range: start..end,
 4766                        },
 4767                        actions.into(),
 4768                    ))
 4769                };
 4770                cx.notify();
 4771            })
 4772            .log_err();
 4773        }));
 4774        None
 4775    }
 4776
 4777    fn start_inline_blame_timer(&mut self, cx: &mut ViewContext<Self>) {
 4778        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 4779            self.show_git_blame_inline = false;
 4780
 4781            self.show_git_blame_inline_delay_task = Some(cx.spawn(|this, mut cx| async move {
 4782                cx.background_executor().timer(delay).await;
 4783
 4784                this.update(&mut cx, |this, cx| {
 4785                    this.show_git_blame_inline = true;
 4786                    cx.notify();
 4787                })
 4788                .log_err();
 4789            }));
 4790        }
 4791    }
 4792
 4793    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 4794        if self.pending_rename.is_some() {
 4795            return None;
 4796        }
 4797
 4798        let project = self.project.clone()?;
 4799        let buffer = self.buffer.read(cx);
 4800        let newest_selection = self.selections.newest_anchor().clone();
 4801        let cursor_position = newest_selection.head();
 4802        let (cursor_buffer, cursor_buffer_position) =
 4803            buffer.text_anchor_for_position(cursor_position, cx)?;
 4804        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 4805        if cursor_buffer != tail_buffer {
 4806            return None;
 4807        }
 4808
 4809        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
 4810            cx.background_executor()
 4811                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
 4812                .await;
 4813
 4814            let highlights = if let Some(highlights) = project
 4815                .update(&mut cx, |project, cx| {
 4816                    project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 4817                })
 4818                .log_err()
 4819            {
 4820                highlights.await.log_err()
 4821            } else {
 4822                None
 4823            };
 4824
 4825            if let Some(highlights) = highlights {
 4826                this.update(&mut cx, |this, cx| {
 4827                    if this.pending_rename.is_some() {
 4828                        return;
 4829                    }
 4830
 4831                    let buffer_id = cursor_position.buffer_id;
 4832                    let buffer = this.buffer.read(cx);
 4833                    if !buffer
 4834                        .text_anchor_for_position(cursor_position, cx)
 4835                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 4836                    {
 4837                        return;
 4838                    }
 4839
 4840                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 4841                    let mut write_ranges = Vec::new();
 4842                    let mut read_ranges = Vec::new();
 4843                    for highlight in highlights {
 4844                        for (excerpt_id, excerpt_range) in
 4845                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
 4846                        {
 4847                            let start = highlight
 4848                                .range
 4849                                .start
 4850                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 4851                            let end = highlight
 4852                                .range
 4853                                .end
 4854                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 4855                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 4856                                continue;
 4857                            }
 4858
 4859                            let range = Anchor {
 4860                                buffer_id,
 4861                                excerpt_id,
 4862                                text_anchor: start,
 4863                            }..Anchor {
 4864                                buffer_id,
 4865                                excerpt_id,
 4866                                text_anchor: end,
 4867                            };
 4868                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 4869                                write_ranges.push(range);
 4870                            } else {
 4871                                read_ranges.push(range);
 4872                            }
 4873                        }
 4874                    }
 4875
 4876                    this.highlight_background::<DocumentHighlightRead>(
 4877                        &read_ranges,
 4878                        |theme| theme.editor_document_highlight_read_background,
 4879                        cx,
 4880                    );
 4881                    this.highlight_background::<DocumentHighlightWrite>(
 4882                        &write_ranges,
 4883                        |theme| theme.editor_document_highlight_write_background,
 4884                        cx,
 4885                    );
 4886                    cx.notify();
 4887                })
 4888                .log_err();
 4889            }
 4890        }));
 4891        None
 4892    }
 4893
 4894    fn refresh_inline_completion(
 4895        &mut self,
 4896        debounce: bool,
 4897        cx: &mut ViewContext<Self>,
 4898    ) -> Option<()> {
 4899        let provider = self.inline_completion_provider()?;
 4900        let cursor = self.selections.newest_anchor().head();
 4901        let (buffer, cursor_buffer_position) =
 4902            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 4903        if !self.show_inline_completions
 4904            || !provider.is_enabled(&buffer, cursor_buffer_position, cx)
 4905        {
 4906            self.discard_inline_completion(false, cx);
 4907            return None;
 4908        }
 4909
 4910        self.update_visible_inline_completion(cx);
 4911        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 4912        Some(())
 4913    }
 4914
 4915    fn cycle_inline_completion(
 4916        &mut self,
 4917        direction: Direction,
 4918        cx: &mut ViewContext<Self>,
 4919    ) -> Option<()> {
 4920        let provider = self.inline_completion_provider()?;
 4921        let cursor = self.selections.newest_anchor().head();
 4922        let (buffer, cursor_buffer_position) =
 4923            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 4924        if !self.show_inline_completions
 4925            || !provider.is_enabled(&buffer, cursor_buffer_position, cx)
 4926        {
 4927            return None;
 4928        }
 4929
 4930        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 4931        self.update_visible_inline_completion(cx);
 4932
 4933        Some(())
 4934    }
 4935
 4936    pub fn show_inline_completion(&mut self, _: &ShowInlineCompletion, cx: &mut ViewContext<Self>) {
 4937        if !self.has_active_inline_completion(cx) {
 4938            self.refresh_inline_completion(false, cx);
 4939            return;
 4940        }
 4941
 4942        self.update_visible_inline_completion(cx);
 4943    }
 4944
 4945    pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext<Self>) {
 4946        self.show_cursor_names(cx);
 4947    }
 4948
 4949    fn show_cursor_names(&mut self, cx: &mut ViewContext<Self>) {
 4950        self.show_cursor_names = true;
 4951        cx.notify();
 4952        cx.spawn(|this, mut cx| async move {
 4953            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 4954            this.update(&mut cx, |this, cx| {
 4955                this.show_cursor_names = false;
 4956                cx.notify()
 4957            })
 4958            .ok()
 4959        })
 4960        .detach();
 4961    }
 4962
 4963    pub fn next_inline_completion(&mut self, _: &NextInlineCompletion, cx: &mut ViewContext<Self>) {
 4964        if self.has_active_inline_completion(cx) {
 4965            self.cycle_inline_completion(Direction::Next, cx);
 4966        } else {
 4967            let is_copilot_disabled = self.refresh_inline_completion(false, cx).is_none();
 4968            if is_copilot_disabled {
 4969                cx.propagate();
 4970            }
 4971        }
 4972    }
 4973
 4974    pub fn previous_inline_completion(
 4975        &mut self,
 4976        _: &PreviousInlineCompletion,
 4977        cx: &mut ViewContext<Self>,
 4978    ) {
 4979        if self.has_active_inline_completion(cx) {
 4980            self.cycle_inline_completion(Direction::Prev, cx);
 4981        } else {
 4982            let is_copilot_disabled = self.refresh_inline_completion(false, cx).is_none();
 4983            if is_copilot_disabled {
 4984                cx.propagate();
 4985            }
 4986        }
 4987    }
 4988
 4989    pub fn accept_inline_completion(
 4990        &mut self,
 4991        _: &AcceptInlineCompletion,
 4992        cx: &mut ViewContext<Self>,
 4993    ) {
 4994        let Some((completion, delete_range)) = self.take_active_inline_completion(cx) else {
 4995            return;
 4996        };
 4997        if let Some(provider) = self.inline_completion_provider() {
 4998            provider.accept(cx);
 4999        }
 5000
 5001        cx.emit(EditorEvent::InputHandled {
 5002            utf16_range_to_replace: None,
 5003            text: completion.text.to_string().into(),
 5004        });
 5005
 5006        if let Some(range) = delete_range {
 5007            self.change_selections(None, cx, |s| s.select_ranges([range]))
 5008        }
 5009        self.insert_with_autoindent_mode(&completion.text.to_string(), None, cx);
 5010        self.refresh_inline_completion(true, cx);
 5011        cx.notify();
 5012    }
 5013
 5014    pub fn accept_partial_inline_completion(
 5015        &mut self,
 5016        _: &AcceptPartialInlineCompletion,
 5017        cx: &mut ViewContext<Self>,
 5018    ) {
 5019        if self.selections.count() == 1 && self.has_active_inline_completion(cx) {
 5020            if let Some((completion, delete_range)) = self.take_active_inline_completion(cx) {
 5021                let mut partial_completion = completion
 5022                    .text
 5023                    .chars()
 5024                    .by_ref()
 5025                    .take_while(|c| c.is_alphabetic())
 5026                    .collect::<String>();
 5027                if partial_completion.is_empty() {
 5028                    partial_completion = completion
 5029                        .text
 5030                        .chars()
 5031                        .by_ref()
 5032                        .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 5033                        .collect::<String>();
 5034                }
 5035
 5036                cx.emit(EditorEvent::InputHandled {
 5037                    utf16_range_to_replace: None,
 5038                    text: partial_completion.clone().into(),
 5039                });
 5040
 5041                if let Some(range) = delete_range {
 5042                    self.change_selections(None, cx, |s| s.select_ranges([range]))
 5043                }
 5044                self.insert_with_autoindent_mode(&partial_completion, None, cx);
 5045
 5046                self.refresh_inline_completion(true, cx);
 5047                cx.notify();
 5048            }
 5049        }
 5050    }
 5051
 5052    fn discard_inline_completion(
 5053        &mut self,
 5054        should_report_inline_completion_event: bool,
 5055        cx: &mut ViewContext<Self>,
 5056    ) -> bool {
 5057        if let Some(provider) = self.inline_completion_provider() {
 5058            provider.discard(should_report_inline_completion_event, cx);
 5059        }
 5060
 5061        self.take_active_inline_completion(cx).is_some()
 5062    }
 5063
 5064    pub fn has_active_inline_completion(&self, cx: &AppContext) -> bool {
 5065        if let Some(completion) = self.active_inline_completion.as_ref() {
 5066            let buffer = self.buffer.read(cx).read(cx);
 5067            completion.0.position.is_valid(&buffer)
 5068        } else {
 5069            false
 5070        }
 5071    }
 5072
 5073    fn take_active_inline_completion(
 5074        &mut self,
 5075        cx: &mut ViewContext<Self>,
 5076    ) -> Option<(Inlay, Option<Range<Anchor>>)> {
 5077        let completion = self.active_inline_completion.take()?;
 5078        self.display_map.update(cx, |map, cx| {
 5079            map.splice_inlays(vec![completion.0.id], Default::default(), cx);
 5080        });
 5081        let buffer = self.buffer.read(cx).read(cx);
 5082
 5083        if completion.0.position.is_valid(&buffer) {
 5084            Some(completion)
 5085        } else {
 5086            None
 5087        }
 5088    }
 5089
 5090    fn update_visible_inline_completion(&mut self, cx: &mut ViewContext<Self>) {
 5091        let selection = self.selections.newest_anchor();
 5092        let cursor = selection.head();
 5093
 5094        let excerpt_id = cursor.excerpt_id;
 5095
 5096        if self.context_menu.read().is_none()
 5097            && self.completion_tasks.is_empty()
 5098            && selection.start == selection.end
 5099        {
 5100            if let Some(provider) = self.inline_completion_provider() {
 5101                if let Some((buffer, cursor_buffer_position)) =
 5102                    self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5103                {
 5104                    if let Some((text, text_anchor_range)) =
 5105                        provider.active_completion_text(&buffer, cursor_buffer_position, cx)
 5106                    {
 5107                        let text = Rope::from(text);
 5108                        let mut to_remove = Vec::new();
 5109                        if let Some(completion) = self.active_inline_completion.take() {
 5110                            to_remove.push(completion.0.id);
 5111                        }
 5112
 5113                        let completion_inlay =
 5114                            Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
 5115
 5116                        let multibuffer_anchor_range = text_anchor_range.and_then(|range| {
 5117                            let snapshot = self.buffer.read(cx).snapshot(cx);
 5118                            Some(
 5119                                snapshot.anchor_in_excerpt(excerpt_id, range.start)?
 5120                                    ..snapshot.anchor_in_excerpt(excerpt_id, range.end)?,
 5121                            )
 5122                        });
 5123                        self.active_inline_completion =
 5124                            Some((completion_inlay.clone(), multibuffer_anchor_range));
 5125
 5126                        self.display_map.update(cx, move |map, cx| {
 5127                            map.splice_inlays(to_remove, vec![completion_inlay], cx)
 5128                        });
 5129                        cx.notify();
 5130                        return;
 5131                    }
 5132                }
 5133            }
 5134        }
 5135
 5136        self.discard_inline_completion(false, cx);
 5137    }
 5138
 5139    fn inline_completion_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 5140        Some(self.inline_completion_provider.as_ref()?.provider.clone())
 5141    }
 5142
 5143    fn render_code_actions_indicator(
 5144        &self,
 5145        _style: &EditorStyle,
 5146        row: DisplayRow,
 5147        is_active: bool,
 5148        cx: &mut ViewContext<Self>,
 5149    ) -> Option<IconButton> {
 5150        if self.available_code_actions.is_some() {
 5151            Some(
 5152                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 5153                    .shape(ui::IconButtonShape::Square)
 5154                    .icon_size(IconSize::XSmall)
 5155                    .icon_color(Color::Muted)
 5156                    .selected(is_active)
 5157                    .on_click(cx.listener(move |editor, _e, cx| {
 5158                        editor.focus(cx);
 5159                        editor.toggle_code_actions(
 5160                            &ToggleCodeActions {
 5161                                deployed_from_indicator: Some(row),
 5162                            },
 5163                            cx,
 5164                        );
 5165                    })),
 5166            )
 5167        } else {
 5168            None
 5169        }
 5170    }
 5171
 5172    fn clear_tasks(&mut self) {
 5173        self.tasks.clear()
 5174    }
 5175
 5176    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 5177        if let Some(_) = self.tasks.insert(key, value) {
 5178            // This case should hopefully be rare, but just in case...
 5179            log::error!("multiple different run targets found on a single line, only the last target will be rendered")
 5180        }
 5181    }
 5182
 5183    fn render_run_indicator(
 5184        &self,
 5185        _style: &EditorStyle,
 5186        is_active: bool,
 5187        row: DisplayRow,
 5188        cx: &mut ViewContext<Self>,
 5189    ) -> IconButton {
 5190        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 5191            .shape(ui::IconButtonShape::Square)
 5192            .icon_size(IconSize::XSmall)
 5193            .icon_color(Color::Muted)
 5194            .selected(is_active)
 5195            .on_click(cx.listener(move |editor, _e, cx| {
 5196                editor.focus(cx);
 5197                editor.toggle_code_actions(
 5198                    &ToggleCodeActions {
 5199                        deployed_from_indicator: Some(row),
 5200                    },
 5201                    cx,
 5202                );
 5203            }))
 5204    }
 5205
 5206    fn close_hunk_diff_button(
 5207        &self,
 5208        hunk: HoveredHunk,
 5209        row: DisplayRow,
 5210        cx: &mut ViewContext<Self>,
 5211    ) -> IconButton {
 5212        IconButton::new(
 5213            ("close_hunk_diff_indicator", row.0 as usize),
 5214            ui::IconName::Close,
 5215        )
 5216        .shape(ui::IconButtonShape::Square)
 5217        .icon_size(IconSize::XSmall)
 5218        .icon_color(Color::Muted)
 5219        .tooltip(|cx| Tooltip::for_action("Close hunk diff", &ToggleHunkDiff, cx))
 5220        .on_click(cx.listener(move |editor, _e, cx| editor.toggle_hovered_hunk(&hunk, cx)))
 5221    }
 5222
 5223    pub fn context_menu_visible(&self) -> bool {
 5224        self.context_menu
 5225            .read()
 5226            .as_ref()
 5227            .map_or(false, |menu| menu.visible())
 5228    }
 5229
 5230    fn render_context_menu(
 5231        &self,
 5232        cursor_position: DisplayPoint,
 5233        style: &EditorStyle,
 5234        max_height: Pixels,
 5235        cx: &mut ViewContext<Editor>,
 5236    ) -> Option<(ContextMenuOrigin, AnyElement)> {
 5237        self.context_menu.read().as_ref().map(|menu| {
 5238            menu.render(
 5239                cursor_position,
 5240                style,
 5241                max_height,
 5242                self.workspace.as_ref().map(|(w, _)| w.clone()),
 5243                cx,
 5244            )
 5245        })
 5246    }
 5247
 5248    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
 5249        cx.notify();
 5250        self.completion_tasks.clear();
 5251        let context_menu = self.context_menu.write().take();
 5252        if context_menu.is_some() {
 5253            self.update_visible_inline_completion(cx);
 5254        }
 5255        context_menu
 5256    }
 5257
 5258    pub fn insert_snippet(
 5259        &mut self,
 5260        insertion_ranges: &[Range<usize>],
 5261        snippet: Snippet,
 5262        cx: &mut ViewContext<Self>,
 5263    ) -> Result<()> {
 5264        struct Tabstop<T> {
 5265            is_end_tabstop: bool,
 5266            ranges: Vec<Range<T>>,
 5267        }
 5268
 5269        let tabstops = self.buffer.update(cx, |buffer, cx| {
 5270            let snippet_text: Arc<str> = snippet.text.clone().into();
 5271            buffer.edit(
 5272                insertion_ranges
 5273                    .iter()
 5274                    .cloned()
 5275                    .map(|range| (range, snippet_text.clone())),
 5276                Some(AutoindentMode::EachLine),
 5277                cx,
 5278            );
 5279
 5280            let snapshot = &*buffer.read(cx);
 5281            let snippet = &snippet;
 5282            snippet
 5283                .tabstops
 5284                .iter()
 5285                .map(|tabstop| {
 5286                    let is_end_tabstop = tabstop.first().map_or(false, |tabstop| {
 5287                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 5288                    });
 5289                    let mut tabstop_ranges = tabstop
 5290                        .iter()
 5291                        .flat_map(|tabstop_range| {
 5292                            let mut delta = 0_isize;
 5293                            insertion_ranges.iter().map(move |insertion_range| {
 5294                                let insertion_start = insertion_range.start as isize + delta;
 5295                                delta +=
 5296                                    snippet.text.len() as isize - insertion_range.len() as isize;
 5297
 5298                                let start = ((insertion_start + tabstop_range.start) as usize)
 5299                                    .min(snapshot.len());
 5300                                let end = ((insertion_start + tabstop_range.end) as usize)
 5301                                    .min(snapshot.len());
 5302                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 5303                            })
 5304                        })
 5305                        .collect::<Vec<_>>();
 5306                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 5307
 5308                    Tabstop {
 5309                        is_end_tabstop,
 5310                        ranges: tabstop_ranges,
 5311                    }
 5312                })
 5313                .collect::<Vec<_>>()
 5314        });
 5315        if let Some(tabstop) = tabstops.first() {
 5316            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5317                s.select_ranges(tabstop.ranges.iter().cloned());
 5318            });
 5319
 5320            // If we're already at the last tabstop and it's at the end of the snippet,
 5321            // we're done, we don't need to keep the state around.
 5322            if !tabstop.is_end_tabstop {
 5323                let ranges = tabstops
 5324                    .into_iter()
 5325                    .map(|tabstop| tabstop.ranges)
 5326                    .collect::<Vec<_>>();
 5327                self.snippet_stack.push(SnippetState {
 5328                    active_index: 0,
 5329                    ranges,
 5330                });
 5331            }
 5332
 5333            // Check whether the just-entered snippet ends with an auto-closable bracket.
 5334            if self.autoclose_regions.is_empty() {
 5335                let snapshot = self.buffer.read(cx).snapshot(cx);
 5336                for selection in &mut self.selections.all::<Point>(cx) {
 5337                    let selection_head = selection.head();
 5338                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 5339                        continue;
 5340                    };
 5341
 5342                    let mut bracket_pair = None;
 5343                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 5344                    let prev_chars = snapshot
 5345                        .reversed_chars_at(selection_head)
 5346                        .collect::<String>();
 5347                    for (pair, enabled) in scope.brackets() {
 5348                        if enabled
 5349                            && pair.close
 5350                            && prev_chars.starts_with(pair.start.as_str())
 5351                            && next_chars.starts_with(pair.end.as_str())
 5352                        {
 5353                            bracket_pair = Some(pair.clone());
 5354                            break;
 5355                        }
 5356                    }
 5357                    if let Some(pair) = bracket_pair {
 5358                        let start = snapshot.anchor_after(selection_head);
 5359                        let end = snapshot.anchor_after(selection_head);
 5360                        self.autoclose_regions.push(AutocloseRegion {
 5361                            selection_id: selection.id,
 5362                            range: start..end,
 5363                            pair,
 5364                        });
 5365                    }
 5366                }
 5367            }
 5368        }
 5369        Ok(())
 5370    }
 5371
 5372    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 5373        self.move_to_snippet_tabstop(Bias::Right, cx)
 5374    }
 5375
 5376    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 5377        self.move_to_snippet_tabstop(Bias::Left, cx)
 5378    }
 5379
 5380    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
 5381        if let Some(mut snippet) = self.snippet_stack.pop() {
 5382            match bias {
 5383                Bias::Left => {
 5384                    if snippet.active_index > 0 {
 5385                        snippet.active_index -= 1;
 5386                    } else {
 5387                        self.snippet_stack.push(snippet);
 5388                        return false;
 5389                    }
 5390                }
 5391                Bias::Right => {
 5392                    if snippet.active_index + 1 < snippet.ranges.len() {
 5393                        snippet.active_index += 1;
 5394                    } else {
 5395                        self.snippet_stack.push(snippet);
 5396                        return false;
 5397                    }
 5398                }
 5399            }
 5400            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 5401                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5402                    s.select_anchor_ranges(current_ranges.iter().cloned())
 5403                });
 5404                // If snippet state is not at the last tabstop, push it back on the stack
 5405                if snippet.active_index + 1 < snippet.ranges.len() {
 5406                    self.snippet_stack.push(snippet);
 5407                }
 5408                return true;
 5409            }
 5410        }
 5411
 5412        false
 5413    }
 5414
 5415    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
 5416        self.transact(cx, |this, cx| {
 5417            this.select_all(&SelectAll, cx);
 5418            this.insert("", cx);
 5419        });
 5420    }
 5421
 5422    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
 5423        self.transact(cx, |this, cx| {
 5424            this.select_autoclose_pair(cx);
 5425            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 5426            if !this.linked_edit_ranges.is_empty() {
 5427                let selections = this.selections.all::<MultiBufferPoint>(cx);
 5428                let snapshot = this.buffer.read(cx).snapshot(cx);
 5429
 5430                for selection in selections.iter() {
 5431                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 5432                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 5433                    if selection_start.buffer_id != selection_end.buffer_id {
 5434                        continue;
 5435                    }
 5436                    if let Some(ranges) =
 5437                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 5438                    {
 5439                        for (buffer, entries) in ranges {
 5440                            linked_ranges.entry(buffer).or_default().extend(entries);
 5441                        }
 5442                    }
 5443                }
 5444            }
 5445
 5446            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 5447            if !this.selections.line_mode {
 5448                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5449                for selection in &mut selections {
 5450                    if selection.is_empty() {
 5451                        let old_head = selection.head();
 5452                        let mut new_head =
 5453                            movement::left(&display_map, old_head.to_display_point(&display_map))
 5454                                .to_point(&display_map);
 5455                        if let Some((buffer, line_buffer_range)) = display_map
 5456                            .buffer_snapshot
 5457                            .buffer_line_for_row(MultiBufferRow(old_head.row))
 5458                        {
 5459                            let indent_size =
 5460                                buffer.indent_size_for_line(line_buffer_range.start.row);
 5461                            let indent_len = match indent_size.kind {
 5462                                IndentKind::Space => {
 5463                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
 5464                                }
 5465                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 5466                            };
 5467                            if old_head.column <= indent_size.len && old_head.column > 0 {
 5468                                let indent_len = indent_len.get();
 5469                                new_head = cmp::min(
 5470                                    new_head,
 5471                                    MultiBufferPoint::new(
 5472                                        old_head.row,
 5473                                        ((old_head.column - 1) / indent_len) * indent_len,
 5474                                    ),
 5475                                );
 5476                            }
 5477                        }
 5478
 5479                        selection.set_head(new_head, SelectionGoal::None);
 5480                    }
 5481                }
 5482            }
 5483
 5484            this.signature_help_state.set_backspace_pressed(true);
 5485            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5486            this.insert("", cx);
 5487            let empty_str: Arc<str> = Arc::from("");
 5488            for (buffer, edits) in linked_ranges {
 5489                let snapshot = buffer.read(cx).snapshot();
 5490                use text::ToPoint as TP;
 5491
 5492                let edits = edits
 5493                    .into_iter()
 5494                    .map(|range| {
 5495                        let end_point = TP::to_point(&range.end, &snapshot);
 5496                        let mut start_point = TP::to_point(&range.start, &snapshot);
 5497
 5498                        if end_point == start_point {
 5499                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 5500                                .saturating_sub(1);
 5501                            start_point = TP::to_point(&offset, &snapshot);
 5502                        };
 5503
 5504                        (start_point..end_point, empty_str.clone())
 5505                    })
 5506                    .sorted_by_key(|(range, _)| range.start)
 5507                    .collect::<Vec<_>>();
 5508                buffer.update(cx, |this, cx| {
 5509                    this.edit(edits, None, cx);
 5510                })
 5511            }
 5512            this.refresh_inline_completion(true, cx);
 5513            linked_editing_ranges::refresh_linked_ranges(this, cx);
 5514        });
 5515    }
 5516
 5517    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
 5518        self.transact(cx, |this, cx| {
 5519            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5520                let line_mode = s.line_mode;
 5521                s.move_with(|map, selection| {
 5522                    if selection.is_empty() && !line_mode {
 5523                        let cursor = movement::right(map, selection.head());
 5524                        selection.end = cursor;
 5525                        selection.reversed = true;
 5526                        selection.goal = SelectionGoal::None;
 5527                    }
 5528                })
 5529            });
 5530            this.insert("", cx);
 5531            this.refresh_inline_completion(true, cx);
 5532        });
 5533    }
 5534
 5535    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
 5536        if self.move_to_prev_snippet_tabstop(cx) {
 5537            return;
 5538        }
 5539
 5540        self.outdent(&Outdent, cx);
 5541    }
 5542
 5543    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
 5544        if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) {
 5545            return;
 5546        }
 5547
 5548        let mut selections = self.selections.all_adjusted(cx);
 5549        let buffer = self.buffer.read(cx);
 5550        let snapshot = buffer.snapshot(cx);
 5551        let rows_iter = selections.iter().map(|s| s.head().row);
 5552        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 5553
 5554        let mut edits = Vec::new();
 5555        let mut prev_edited_row = 0;
 5556        let mut row_delta = 0;
 5557        for selection in &mut selections {
 5558            if selection.start.row != prev_edited_row {
 5559                row_delta = 0;
 5560            }
 5561            prev_edited_row = selection.end.row;
 5562
 5563            // If the selection is non-empty, then increase the indentation of the selected lines.
 5564            if !selection.is_empty() {
 5565                row_delta =
 5566                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 5567                continue;
 5568            }
 5569
 5570            // If the selection is empty and the cursor is in the leading whitespace before the
 5571            // suggested indentation, then auto-indent the line.
 5572            let cursor = selection.head();
 5573            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 5574            if let Some(suggested_indent) =
 5575                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 5576            {
 5577                if cursor.column < suggested_indent.len
 5578                    && cursor.column <= current_indent.len
 5579                    && current_indent.len <= suggested_indent.len
 5580                {
 5581                    selection.start = Point::new(cursor.row, suggested_indent.len);
 5582                    selection.end = selection.start;
 5583                    if row_delta == 0 {
 5584                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 5585                            cursor.row,
 5586                            current_indent,
 5587                            suggested_indent,
 5588                        ));
 5589                        row_delta = suggested_indent.len - current_indent.len;
 5590                    }
 5591                    continue;
 5592                }
 5593            }
 5594
 5595            // Otherwise, insert a hard or soft tab.
 5596            let settings = buffer.settings_at(cursor, cx);
 5597            let tab_size = if settings.hard_tabs {
 5598                IndentSize::tab()
 5599            } else {
 5600                let tab_size = settings.tab_size.get();
 5601                let char_column = snapshot
 5602                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 5603                    .flat_map(str::chars)
 5604                    .count()
 5605                    + row_delta as usize;
 5606                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 5607                IndentSize::spaces(chars_to_next_tab_stop)
 5608            };
 5609            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 5610            selection.end = selection.start;
 5611            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 5612            row_delta += tab_size.len;
 5613        }
 5614
 5615        self.transact(cx, |this, cx| {
 5616            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 5617            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5618            this.refresh_inline_completion(true, cx);
 5619        });
 5620    }
 5621
 5622    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
 5623        if self.read_only(cx) {
 5624            return;
 5625        }
 5626        let mut selections = self.selections.all::<Point>(cx);
 5627        let mut prev_edited_row = 0;
 5628        let mut row_delta = 0;
 5629        let mut edits = Vec::new();
 5630        let buffer = self.buffer.read(cx);
 5631        let snapshot = buffer.snapshot(cx);
 5632        for selection in &mut selections {
 5633            if selection.start.row != prev_edited_row {
 5634                row_delta = 0;
 5635            }
 5636            prev_edited_row = selection.end.row;
 5637
 5638            row_delta =
 5639                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 5640        }
 5641
 5642        self.transact(cx, |this, cx| {
 5643            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 5644            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5645        });
 5646    }
 5647
 5648    fn indent_selection(
 5649        buffer: &MultiBuffer,
 5650        snapshot: &MultiBufferSnapshot,
 5651        selection: &mut Selection<Point>,
 5652        edits: &mut Vec<(Range<Point>, String)>,
 5653        delta_for_start_row: u32,
 5654        cx: &AppContext,
 5655    ) -> u32 {
 5656        let settings = buffer.settings_at(selection.start, cx);
 5657        let tab_size = settings.tab_size.get();
 5658        let indent_kind = if settings.hard_tabs {
 5659            IndentKind::Tab
 5660        } else {
 5661            IndentKind::Space
 5662        };
 5663        let mut start_row = selection.start.row;
 5664        let mut end_row = selection.end.row + 1;
 5665
 5666        // If a selection ends at the beginning of a line, don't indent
 5667        // that last line.
 5668        if selection.end.column == 0 && selection.end.row > selection.start.row {
 5669            end_row -= 1;
 5670        }
 5671
 5672        // Avoid re-indenting a row that has already been indented by a
 5673        // previous selection, but still update this selection's column
 5674        // to reflect that indentation.
 5675        if delta_for_start_row > 0 {
 5676            start_row += 1;
 5677            selection.start.column += delta_for_start_row;
 5678            if selection.end.row == selection.start.row {
 5679                selection.end.column += delta_for_start_row;
 5680            }
 5681        }
 5682
 5683        let mut delta_for_end_row = 0;
 5684        let has_multiple_rows = start_row + 1 != end_row;
 5685        for row in start_row..end_row {
 5686            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 5687            let indent_delta = match (current_indent.kind, indent_kind) {
 5688                (IndentKind::Space, IndentKind::Space) => {
 5689                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 5690                    IndentSize::spaces(columns_to_next_tab_stop)
 5691                }
 5692                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 5693                (_, IndentKind::Tab) => IndentSize::tab(),
 5694            };
 5695
 5696            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 5697                0
 5698            } else {
 5699                selection.start.column
 5700            };
 5701            let row_start = Point::new(row, start);
 5702            edits.push((
 5703                row_start..row_start,
 5704                indent_delta.chars().collect::<String>(),
 5705            ));
 5706
 5707            // Update this selection's endpoints to reflect the indentation.
 5708            if row == selection.start.row {
 5709                selection.start.column += indent_delta.len;
 5710            }
 5711            if row == selection.end.row {
 5712                selection.end.column += indent_delta.len;
 5713                delta_for_end_row = indent_delta.len;
 5714            }
 5715        }
 5716
 5717        if selection.start.row == selection.end.row {
 5718            delta_for_start_row + delta_for_end_row
 5719        } else {
 5720            delta_for_end_row
 5721        }
 5722    }
 5723
 5724    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
 5725        if self.read_only(cx) {
 5726            return;
 5727        }
 5728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5729        let selections = self.selections.all::<Point>(cx);
 5730        let mut deletion_ranges = Vec::new();
 5731        let mut last_outdent = None;
 5732        {
 5733            let buffer = self.buffer.read(cx);
 5734            let snapshot = buffer.snapshot(cx);
 5735            for selection in &selections {
 5736                let settings = buffer.settings_at(selection.start, cx);
 5737                let tab_size = settings.tab_size.get();
 5738                let mut rows = selection.spanned_rows(false, &display_map);
 5739
 5740                // Avoid re-outdenting a row that has already been outdented by a
 5741                // previous selection.
 5742                if let Some(last_row) = last_outdent {
 5743                    if last_row == rows.start {
 5744                        rows.start = rows.start.next_row();
 5745                    }
 5746                }
 5747                let has_multiple_rows = rows.len() > 1;
 5748                for row in rows.iter_rows() {
 5749                    let indent_size = snapshot.indent_size_for_line(row);
 5750                    if indent_size.len > 0 {
 5751                        let deletion_len = match indent_size.kind {
 5752                            IndentKind::Space => {
 5753                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 5754                                if columns_to_prev_tab_stop == 0 {
 5755                                    tab_size
 5756                                } else {
 5757                                    columns_to_prev_tab_stop
 5758                                }
 5759                            }
 5760                            IndentKind::Tab => 1,
 5761                        };
 5762                        let start = if has_multiple_rows
 5763                            || deletion_len > selection.start.column
 5764                            || indent_size.len < selection.start.column
 5765                        {
 5766                            0
 5767                        } else {
 5768                            selection.start.column - deletion_len
 5769                        };
 5770                        deletion_ranges.push(
 5771                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 5772                        );
 5773                        last_outdent = Some(row);
 5774                    }
 5775                }
 5776            }
 5777        }
 5778
 5779        self.transact(cx, |this, cx| {
 5780            this.buffer.update(cx, |buffer, cx| {
 5781                let empty_str: Arc<str> = Arc::default();
 5782                buffer.edit(
 5783                    deletion_ranges
 5784                        .into_iter()
 5785                        .map(|range| (range, empty_str.clone())),
 5786                    None,
 5787                    cx,
 5788                );
 5789            });
 5790            let selections = this.selections.all::<usize>(cx);
 5791            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5792        });
 5793    }
 5794
 5795    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
 5796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5797        let selections = self.selections.all::<Point>(cx);
 5798
 5799        let mut new_cursors = Vec::new();
 5800        let mut edit_ranges = Vec::new();
 5801        let mut selections = selections.iter().peekable();
 5802        while let Some(selection) = selections.next() {
 5803            let mut rows = selection.spanned_rows(false, &display_map);
 5804            let goal_display_column = selection.head().to_display_point(&display_map).column();
 5805
 5806            // Accumulate contiguous regions of rows that we want to delete.
 5807            while let Some(next_selection) = selections.peek() {
 5808                let next_rows = next_selection.spanned_rows(false, &display_map);
 5809                if next_rows.start <= rows.end {
 5810                    rows.end = next_rows.end;
 5811                    selections.next().unwrap();
 5812                } else {
 5813                    break;
 5814                }
 5815            }
 5816
 5817            let buffer = &display_map.buffer_snapshot;
 5818            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 5819            let edit_end;
 5820            let cursor_buffer_row;
 5821            if buffer.max_point().row >= rows.end.0 {
 5822                // If there's a line after the range, delete the \n from the end of the row range
 5823                // and position the cursor on the next line.
 5824                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 5825                cursor_buffer_row = rows.end;
 5826            } else {
 5827                // If there isn't a line after the range, delete the \n from the line before the
 5828                // start of the row range and position the cursor there.
 5829                edit_start = edit_start.saturating_sub(1);
 5830                edit_end = buffer.len();
 5831                cursor_buffer_row = rows.start.previous_row();
 5832            }
 5833
 5834            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 5835            *cursor.column_mut() =
 5836                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 5837
 5838            new_cursors.push((
 5839                selection.id,
 5840                buffer.anchor_after(cursor.to_point(&display_map)),
 5841            ));
 5842            edit_ranges.push(edit_start..edit_end);
 5843        }
 5844
 5845        self.transact(cx, |this, cx| {
 5846            let buffer = this.buffer.update(cx, |buffer, cx| {
 5847                let empty_str: Arc<str> = Arc::default();
 5848                buffer.edit(
 5849                    edit_ranges
 5850                        .into_iter()
 5851                        .map(|range| (range, empty_str.clone())),
 5852                    None,
 5853                    cx,
 5854                );
 5855                buffer.snapshot(cx)
 5856            });
 5857            let new_selections = new_cursors
 5858                .into_iter()
 5859                .map(|(id, cursor)| {
 5860                    let cursor = cursor.to_point(&buffer);
 5861                    Selection {
 5862                        id,
 5863                        start: cursor,
 5864                        end: cursor,
 5865                        reversed: false,
 5866                        goal: SelectionGoal::None,
 5867                    }
 5868                })
 5869                .collect();
 5870
 5871            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5872                s.select(new_selections);
 5873            });
 5874        });
 5875    }
 5876
 5877    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
 5878        if self.read_only(cx) {
 5879            return;
 5880        }
 5881        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 5882        for selection in self.selections.all::<Point>(cx) {
 5883            let start = MultiBufferRow(selection.start.row);
 5884            let end = if selection.start.row == selection.end.row {
 5885                MultiBufferRow(selection.start.row + 1)
 5886            } else {
 5887                MultiBufferRow(selection.end.row)
 5888            };
 5889
 5890            if let Some(last_row_range) = row_ranges.last_mut() {
 5891                if start <= last_row_range.end {
 5892                    last_row_range.end = end;
 5893                    continue;
 5894                }
 5895            }
 5896            row_ranges.push(start..end);
 5897        }
 5898
 5899        let snapshot = self.buffer.read(cx).snapshot(cx);
 5900        let mut cursor_positions = Vec::new();
 5901        for row_range in &row_ranges {
 5902            let anchor = snapshot.anchor_before(Point::new(
 5903                row_range.end.previous_row().0,
 5904                snapshot.line_len(row_range.end.previous_row()),
 5905            ));
 5906            cursor_positions.push(anchor..anchor);
 5907        }
 5908
 5909        self.transact(cx, |this, cx| {
 5910            for row_range in row_ranges.into_iter().rev() {
 5911                for row in row_range.iter_rows().rev() {
 5912                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 5913                    let next_line_row = row.next_row();
 5914                    let indent = snapshot.indent_size_for_line(next_line_row);
 5915                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 5916
 5917                    let replace = if snapshot.line_len(next_line_row) > indent.len {
 5918                        " "
 5919                    } else {
 5920                        ""
 5921                    };
 5922
 5923                    this.buffer.update(cx, |buffer, cx| {
 5924                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 5925                    });
 5926                }
 5927            }
 5928
 5929            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5930                s.select_anchor_ranges(cursor_positions)
 5931            });
 5932        });
 5933    }
 5934
 5935    pub fn sort_lines_case_sensitive(
 5936        &mut self,
 5937        _: &SortLinesCaseSensitive,
 5938        cx: &mut ViewContext<Self>,
 5939    ) {
 5940        self.manipulate_lines(cx, |lines| lines.sort())
 5941    }
 5942
 5943    pub fn sort_lines_case_insensitive(
 5944        &mut self,
 5945        _: &SortLinesCaseInsensitive,
 5946        cx: &mut ViewContext<Self>,
 5947    ) {
 5948        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
 5949    }
 5950
 5951    pub fn unique_lines_case_insensitive(
 5952        &mut self,
 5953        _: &UniqueLinesCaseInsensitive,
 5954        cx: &mut ViewContext<Self>,
 5955    ) {
 5956        self.manipulate_lines(cx, |lines| {
 5957            let mut seen = HashSet::default();
 5958            lines.retain(|line| seen.insert(line.to_lowercase()));
 5959        })
 5960    }
 5961
 5962    pub fn unique_lines_case_sensitive(
 5963        &mut self,
 5964        _: &UniqueLinesCaseSensitive,
 5965        cx: &mut ViewContext<Self>,
 5966    ) {
 5967        self.manipulate_lines(cx, |lines| {
 5968            let mut seen = HashSet::default();
 5969            lines.retain(|line| seen.insert(*line));
 5970        })
 5971    }
 5972
 5973    pub fn revert_file(&mut self, _: &RevertFile, cx: &mut ViewContext<Self>) {
 5974        let mut revert_changes = HashMap::default();
 5975        let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 5976        for hunk in hunks_for_rows(
 5977            Some(MultiBufferRow(0)..multi_buffer_snapshot.max_buffer_row()).into_iter(),
 5978            &multi_buffer_snapshot,
 5979        ) {
 5980            Self::prepare_revert_change(&mut revert_changes, &self.buffer(), &hunk, cx);
 5981        }
 5982        if !revert_changes.is_empty() {
 5983            self.transact(cx, |editor, cx| {
 5984                editor.revert(revert_changes, cx);
 5985            });
 5986        }
 5987    }
 5988
 5989    pub fn revert_selected_hunks(&mut self, _: &RevertSelectedHunks, cx: &mut ViewContext<Self>) {
 5990        let revert_changes = self.gather_revert_changes(&self.selections.disjoint_anchors(), cx);
 5991        if !revert_changes.is_empty() {
 5992            self.transact(cx, |editor, cx| {
 5993                editor.revert(revert_changes, cx);
 5994            });
 5995        }
 5996    }
 5997
 5998    pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
 5999        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 6000            let project_path = buffer.read(cx).project_path(cx)?;
 6001            let project = self.project.as_ref()?.read(cx);
 6002            let entry = project.entry_for_path(&project_path, cx)?;
 6003            let abs_path = project.absolute_path(&project_path, cx)?;
 6004            let parent = if entry.is_symlink {
 6005                abs_path.canonicalize().ok()?
 6006            } else {
 6007                abs_path
 6008            }
 6009            .parent()?
 6010            .to_path_buf();
 6011            Some(parent)
 6012        }) {
 6013            cx.dispatch_action(OpenTerminal { working_directory }.boxed_clone());
 6014        }
 6015    }
 6016
 6017    fn gather_revert_changes(
 6018        &mut self,
 6019        selections: &[Selection<Anchor>],
 6020        cx: &mut ViewContext<'_, Editor>,
 6021    ) -> HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>> {
 6022        let mut revert_changes = HashMap::default();
 6023        let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6024        for hunk in hunks_for_selections(&multi_buffer_snapshot, selections) {
 6025            Self::prepare_revert_change(&mut revert_changes, self.buffer(), &hunk, cx);
 6026        }
 6027        revert_changes
 6028    }
 6029
 6030    pub fn prepare_revert_change(
 6031        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 6032        multi_buffer: &Model<MultiBuffer>,
 6033        hunk: &DiffHunk<MultiBufferRow>,
 6034        cx: &AppContext,
 6035    ) -> Option<()> {
 6036        let buffer = multi_buffer.read(cx).buffer(hunk.buffer_id)?;
 6037        let buffer = buffer.read(cx);
 6038        let original_text = buffer.diff_base()?.slice(hunk.diff_base_byte_range.clone());
 6039        let buffer_snapshot = buffer.snapshot();
 6040        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 6041        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 6042            probe
 6043                .0
 6044                .start
 6045                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 6046                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 6047        }) {
 6048            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 6049            Some(())
 6050        } else {
 6051            None
 6052        }
 6053    }
 6054
 6055    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
 6056        self.manipulate_lines(cx, |lines| lines.reverse())
 6057    }
 6058
 6059    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
 6060        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
 6061    }
 6062
 6063    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 6064    where
 6065        Fn: FnMut(&mut Vec<&str>),
 6066    {
 6067        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6068        let buffer = self.buffer.read(cx).snapshot(cx);
 6069
 6070        let mut edits = Vec::new();
 6071
 6072        let selections = self.selections.all::<Point>(cx);
 6073        let mut selections = selections.iter().peekable();
 6074        let mut contiguous_row_selections = Vec::new();
 6075        let mut new_selections = Vec::new();
 6076        let mut added_lines = 0;
 6077        let mut removed_lines = 0;
 6078
 6079        while let Some(selection) = selections.next() {
 6080            let (start_row, end_row) = consume_contiguous_rows(
 6081                &mut contiguous_row_selections,
 6082                selection,
 6083                &display_map,
 6084                &mut selections,
 6085            );
 6086
 6087            let start_point = Point::new(start_row.0, 0);
 6088            let end_point = Point::new(
 6089                end_row.previous_row().0,
 6090                buffer.line_len(end_row.previous_row()),
 6091            );
 6092            let text = buffer
 6093                .text_for_range(start_point..end_point)
 6094                .collect::<String>();
 6095
 6096            let mut lines = text.split('\n').collect_vec();
 6097
 6098            let lines_before = lines.len();
 6099            callback(&mut lines);
 6100            let lines_after = lines.len();
 6101
 6102            edits.push((start_point..end_point, lines.join("\n")));
 6103
 6104            // Selections must change based on added and removed line count
 6105            let start_row =
 6106                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 6107            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 6108            new_selections.push(Selection {
 6109                id: selection.id,
 6110                start: start_row,
 6111                end: end_row,
 6112                goal: SelectionGoal::None,
 6113                reversed: selection.reversed,
 6114            });
 6115
 6116            if lines_after > lines_before {
 6117                added_lines += lines_after - lines_before;
 6118            } else if lines_before > lines_after {
 6119                removed_lines += lines_before - lines_after;
 6120            }
 6121        }
 6122
 6123        self.transact(cx, |this, cx| {
 6124            let buffer = this.buffer.update(cx, |buffer, cx| {
 6125                buffer.edit(edits, None, cx);
 6126                buffer.snapshot(cx)
 6127            });
 6128
 6129            // Recalculate offsets on newly edited buffer
 6130            let new_selections = new_selections
 6131                .iter()
 6132                .map(|s| {
 6133                    let start_point = Point::new(s.start.0, 0);
 6134                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 6135                    Selection {
 6136                        id: s.id,
 6137                        start: buffer.point_to_offset(start_point),
 6138                        end: buffer.point_to_offset(end_point),
 6139                        goal: s.goal,
 6140                        reversed: s.reversed,
 6141                    }
 6142                })
 6143                .collect();
 6144
 6145            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6146                s.select(new_selections);
 6147            });
 6148
 6149            this.request_autoscroll(Autoscroll::fit(), cx);
 6150        });
 6151    }
 6152
 6153    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
 6154        self.manipulate_text(cx, |text| text.to_uppercase())
 6155    }
 6156
 6157    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
 6158        self.manipulate_text(cx, |text| text.to_lowercase())
 6159    }
 6160
 6161    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
 6162        self.manipulate_text(cx, |text| {
 6163            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 6164            // https://github.com/rutrum/convert-case/issues/16
 6165            text.split('\n')
 6166                .map(|line| line.to_case(Case::Title))
 6167                .join("\n")
 6168        })
 6169    }
 6170
 6171    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
 6172        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
 6173    }
 6174
 6175    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
 6176        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
 6177    }
 6178
 6179    pub fn convert_to_upper_camel_case(
 6180        &mut self,
 6181        _: &ConvertToUpperCamelCase,
 6182        cx: &mut ViewContext<Self>,
 6183    ) {
 6184        self.manipulate_text(cx, |text| {
 6185            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 6186            // https://github.com/rutrum/convert-case/issues/16
 6187            text.split('\n')
 6188                .map(|line| line.to_case(Case::UpperCamel))
 6189                .join("\n")
 6190        })
 6191    }
 6192
 6193    pub fn convert_to_lower_camel_case(
 6194        &mut self,
 6195        _: &ConvertToLowerCamelCase,
 6196        cx: &mut ViewContext<Self>,
 6197    ) {
 6198        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
 6199    }
 6200
 6201    pub fn convert_to_opposite_case(
 6202        &mut self,
 6203        _: &ConvertToOppositeCase,
 6204        cx: &mut ViewContext<Self>,
 6205    ) {
 6206        self.manipulate_text(cx, |text| {
 6207            text.chars()
 6208                .fold(String::with_capacity(text.len()), |mut t, c| {
 6209                    if c.is_uppercase() {
 6210                        t.extend(c.to_lowercase());
 6211                    } else {
 6212                        t.extend(c.to_uppercase());
 6213                    }
 6214                    t
 6215                })
 6216        })
 6217    }
 6218
 6219    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 6220    where
 6221        Fn: FnMut(&str) -> String,
 6222    {
 6223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6224        let buffer = self.buffer.read(cx).snapshot(cx);
 6225
 6226        let mut new_selections = Vec::new();
 6227        let mut edits = Vec::new();
 6228        let mut selection_adjustment = 0i32;
 6229
 6230        for selection in self.selections.all::<usize>(cx) {
 6231            let selection_is_empty = selection.is_empty();
 6232
 6233            let (start, end) = if selection_is_empty {
 6234                let word_range = movement::surrounding_word(
 6235                    &display_map,
 6236                    selection.start.to_display_point(&display_map),
 6237                );
 6238                let start = word_range.start.to_offset(&display_map, Bias::Left);
 6239                let end = word_range.end.to_offset(&display_map, Bias::Left);
 6240                (start, end)
 6241            } else {
 6242                (selection.start, selection.end)
 6243            };
 6244
 6245            let text = buffer.text_for_range(start..end).collect::<String>();
 6246            let old_length = text.len() as i32;
 6247            let text = callback(&text);
 6248
 6249            new_selections.push(Selection {
 6250                start: (start as i32 - selection_adjustment) as usize,
 6251                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 6252                goal: SelectionGoal::None,
 6253                ..selection
 6254            });
 6255
 6256            selection_adjustment += old_length - text.len() as i32;
 6257
 6258            edits.push((start..end, text));
 6259        }
 6260
 6261        self.transact(cx, |this, cx| {
 6262            this.buffer.update(cx, |buffer, cx| {
 6263                buffer.edit(edits, None, cx);
 6264            });
 6265
 6266            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6267                s.select(new_selections);
 6268            });
 6269
 6270            this.request_autoscroll(Autoscroll::fit(), cx);
 6271        });
 6272    }
 6273
 6274    pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext<Self>) {
 6275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6276        let buffer = &display_map.buffer_snapshot;
 6277        let selections = self.selections.all::<Point>(cx);
 6278
 6279        let mut edits = Vec::new();
 6280        let mut selections_iter = selections.iter().peekable();
 6281        while let Some(selection) = selections_iter.next() {
 6282            // Avoid duplicating the same lines twice.
 6283            let mut rows = selection.spanned_rows(false, &display_map);
 6284
 6285            while let Some(next_selection) = selections_iter.peek() {
 6286                let next_rows = next_selection.spanned_rows(false, &display_map);
 6287                if next_rows.start < rows.end {
 6288                    rows.end = next_rows.end;
 6289                    selections_iter.next().unwrap();
 6290                } else {
 6291                    break;
 6292                }
 6293            }
 6294
 6295            // Copy the text from the selected row region and splice it either at the start
 6296            // or end of the region.
 6297            let start = Point::new(rows.start.0, 0);
 6298            let end = Point::new(
 6299                rows.end.previous_row().0,
 6300                buffer.line_len(rows.end.previous_row()),
 6301            );
 6302            let text = buffer
 6303                .text_for_range(start..end)
 6304                .chain(Some("\n"))
 6305                .collect::<String>();
 6306            let insert_location = if upwards {
 6307                Point::new(rows.end.0, 0)
 6308            } else {
 6309                start
 6310            };
 6311            edits.push((insert_location..insert_location, text));
 6312        }
 6313
 6314        self.transact(cx, |this, cx| {
 6315            this.buffer.update(cx, |buffer, cx| {
 6316                buffer.edit(edits, None, cx);
 6317            });
 6318
 6319            this.request_autoscroll(Autoscroll::fit(), cx);
 6320        });
 6321    }
 6322
 6323    pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext<Self>) {
 6324        self.duplicate_line(true, cx);
 6325    }
 6326
 6327    pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext<Self>) {
 6328        self.duplicate_line(false, cx);
 6329    }
 6330
 6331    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
 6332        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6333        let buffer = self.buffer.read(cx).snapshot(cx);
 6334
 6335        let mut edits = Vec::new();
 6336        let mut unfold_ranges = Vec::new();
 6337        let mut refold_ranges = Vec::new();
 6338
 6339        let selections = self.selections.all::<Point>(cx);
 6340        let mut selections = selections.iter().peekable();
 6341        let mut contiguous_row_selections = Vec::new();
 6342        let mut new_selections = Vec::new();
 6343
 6344        while let Some(selection) = selections.next() {
 6345            // Find all the selections that span a contiguous row range
 6346            let (start_row, end_row) = consume_contiguous_rows(
 6347                &mut contiguous_row_selections,
 6348                selection,
 6349                &display_map,
 6350                &mut selections,
 6351            );
 6352
 6353            // Move the text spanned by the row range to be before the line preceding the row range
 6354            if start_row.0 > 0 {
 6355                let range_to_move = Point::new(
 6356                    start_row.previous_row().0,
 6357                    buffer.line_len(start_row.previous_row()),
 6358                )
 6359                    ..Point::new(
 6360                        end_row.previous_row().0,
 6361                        buffer.line_len(end_row.previous_row()),
 6362                    );
 6363                let insertion_point = display_map
 6364                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 6365                    .0;
 6366
 6367                // Don't move lines across excerpts
 6368                if buffer
 6369                    .excerpt_boundaries_in_range((
 6370                        Bound::Excluded(insertion_point),
 6371                        Bound::Included(range_to_move.end),
 6372                    ))
 6373                    .next()
 6374                    .is_none()
 6375                {
 6376                    let text = buffer
 6377                        .text_for_range(range_to_move.clone())
 6378                        .flat_map(|s| s.chars())
 6379                        .skip(1)
 6380                        .chain(['\n'])
 6381                        .collect::<String>();
 6382
 6383                    edits.push((
 6384                        buffer.anchor_after(range_to_move.start)
 6385                            ..buffer.anchor_before(range_to_move.end),
 6386                        String::new(),
 6387                    ));
 6388                    let insertion_anchor = buffer.anchor_after(insertion_point);
 6389                    edits.push((insertion_anchor..insertion_anchor, text));
 6390
 6391                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 6392
 6393                    // Move selections up
 6394                    new_selections.extend(contiguous_row_selections.drain(..).map(
 6395                        |mut selection| {
 6396                            selection.start.row -= row_delta;
 6397                            selection.end.row -= row_delta;
 6398                            selection
 6399                        },
 6400                    ));
 6401
 6402                    // Move folds up
 6403                    unfold_ranges.push(range_to_move.clone());
 6404                    for fold in display_map.folds_in_range(
 6405                        buffer.anchor_before(range_to_move.start)
 6406                            ..buffer.anchor_after(range_to_move.end),
 6407                    ) {
 6408                        let mut start = fold.range.start.to_point(&buffer);
 6409                        let mut end = fold.range.end.to_point(&buffer);
 6410                        start.row -= row_delta;
 6411                        end.row -= row_delta;
 6412                        refold_ranges.push((start..end, fold.placeholder.clone()));
 6413                    }
 6414                }
 6415            }
 6416
 6417            // If we didn't move line(s), preserve the existing selections
 6418            new_selections.append(&mut contiguous_row_selections);
 6419        }
 6420
 6421        self.transact(cx, |this, cx| {
 6422            this.unfold_ranges(unfold_ranges, true, true, cx);
 6423            this.buffer.update(cx, |buffer, cx| {
 6424                for (range, text) in edits {
 6425                    buffer.edit([(range, text)], None, cx);
 6426                }
 6427            });
 6428            this.fold_ranges(refold_ranges, true, cx);
 6429            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6430                s.select(new_selections);
 6431            })
 6432        });
 6433    }
 6434
 6435    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
 6436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6437        let buffer = self.buffer.read(cx).snapshot(cx);
 6438
 6439        let mut edits = Vec::new();
 6440        let mut unfold_ranges = Vec::new();
 6441        let mut refold_ranges = Vec::new();
 6442
 6443        let selections = self.selections.all::<Point>(cx);
 6444        let mut selections = selections.iter().peekable();
 6445        let mut contiguous_row_selections = Vec::new();
 6446        let mut new_selections = Vec::new();
 6447
 6448        while let Some(selection) = selections.next() {
 6449            // Find all the selections that span a contiguous row range
 6450            let (start_row, end_row) = consume_contiguous_rows(
 6451                &mut contiguous_row_selections,
 6452                selection,
 6453                &display_map,
 6454                &mut selections,
 6455            );
 6456
 6457            // Move the text spanned by the row range to be after the last line of the row range
 6458            if end_row.0 <= buffer.max_point().row {
 6459                let range_to_move =
 6460                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 6461                let insertion_point = display_map
 6462                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 6463                    .0;
 6464
 6465                // Don't move lines across excerpt boundaries
 6466                if buffer
 6467                    .excerpt_boundaries_in_range((
 6468                        Bound::Excluded(range_to_move.start),
 6469                        Bound::Included(insertion_point),
 6470                    ))
 6471                    .next()
 6472                    .is_none()
 6473                {
 6474                    let mut text = String::from("\n");
 6475                    text.extend(buffer.text_for_range(range_to_move.clone()));
 6476                    text.pop(); // Drop trailing newline
 6477                    edits.push((
 6478                        buffer.anchor_after(range_to_move.start)
 6479                            ..buffer.anchor_before(range_to_move.end),
 6480                        String::new(),
 6481                    ));
 6482                    let insertion_anchor = buffer.anchor_after(insertion_point);
 6483                    edits.push((insertion_anchor..insertion_anchor, text));
 6484
 6485                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 6486
 6487                    // Move selections down
 6488                    new_selections.extend(contiguous_row_selections.drain(..).map(
 6489                        |mut selection| {
 6490                            selection.start.row += row_delta;
 6491                            selection.end.row += row_delta;
 6492                            selection
 6493                        },
 6494                    ));
 6495
 6496                    // Move folds down
 6497                    unfold_ranges.push(range_to_move.clone());
 6498                    for fold in display_map.folds_in_range(
 6499                        buffer.anchor_before(range_to_move.start)
 6500                            ..buffer.anchor_after(range_to_move.end),
 6501                    ) {
 6502                        let mut start = fold.range.start.to_point(&buffer);
 6503                        let mut end = fold.range.end.to_point(&buffer);
 6504                        start.row += row_delta;
 6505                        end.row += row_delta;
 6506                        refold_ranges.push((start..end, fold.placeholder.clone()));
 6507                    }
 6508                }
 6509            }
 6510
 6511            // If we didn't move line(s), preserve the existing selections
 6512            new_selections.append(&mut contiguous_row_selections);
 6513        }
 6514
 6515        self.transact(cx, |this, cx| {
 6516            this.unfold_ranges(unfold_ranges, true, true, cx);
 6517            this.buffer.update(cx, |buffer, cx| {
 6518                for (range, text) in edits {
 6519                    buffer.edit([(range, text)], None, cx);
 6520                }
 6521            });
 6522            this.fold_ranges(refold_ranges, true, cx);
 6523            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 6524        });
 6525    }
 6526
 6527    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
 6528        let text_layout_details = &self.text_layout_details(cx);
 6529        self.transact(cx, |this, cx| {
 6530            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6531                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 6532                let line_mode = s.line_mode;
 6533                s.move_with(|display_map, selection| {
 6534                    if !selection.is_empty() || line_mode {
 6535                        return;
 6536                    }
 6537
 6538                    let mut head = selection.head();
 6539                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 6540                    if head.column() == display_map.line_len(head.row()) {
 6541                        transpose_offset = display_map
 6542                            .buffer_snapshot
 6543                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6544                    }
 6545
 6546                    if transpose_offset == 0 {
 6547                        return;
 6548                    }
 6549
 6550                    *head.column_mut() += 1;
 6551                    head = display_map.clip_point(head, Bias::Right);
 6552                    let goal = SelectionGoal::HorizontalPosition(
 6553                        display_map
 6554                            .x_for_display_point(head, &text_layout_details)
 6555                            .into(),
 6556                    );
 6557                    selection.collapse_to(head, goal);
 6558
 6559                    let transpose_start = display_map
 6560                        .buffer_snapshot
 6561                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 6562                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 6563                        let transpose_end = display_map
 6564                            .buffer_snapshot
 6565                            .clip_offset(transpose_offset + 1, Bias::Right);
 6566                        if let Some(ch) =
 6567                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 6568                        {
 6569                            edits.push((transpose_start..transpose_offset, String::new()));
 6570                            edits.push((transpose_end..transpose_end, ch.to_string()));
 6571                        }
 6572                    }
 6573                });
 6574                edits
 6575            });
 6576            this.buffer
 6577                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 6578            let selections = this.selections.all::<usize>(cx);
 6579            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6580                s.select(selections);
 6581            });
 6582        });
 6583    }
 6584
 6585    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
 6586        let mut text = String::new();
 6587        let buffer = self.buffer.read(cx).snapshot(cx);
 6588        let mut selections = self.selections.all::<Point>(cx);
 6589        let mut clipboard_selections = Vec::with_capacity(selections.len());
 6590        {
 6591            let max_point = buffer.max_point();
 6592            let mut is_first = true;
 6593            for selection in &mut selections {
 6594                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 6595                if is_entire_line {
 6596                    selection.start = Point::new(selection.start.row, 0);
 6597                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 6598                    selection.goal = SelectionGoal::None;
 6599                }
 6600                if is_first {
 6601                    is_first = false;
 6602                } else {
 6603                    text += "\n";
 6604                }
 6605                let mut len = 0;
 6606                for chunk in buffer.text_for_range(selection.start..selection.end) {
 6607                    text.push_str(chunk);
 6608                    len += chunk.len();
 6609                }
 6610                clipboard_selections.push(ClipboardSelection {
 6611                    len,
 6612                    is_entire_line,
 6613                    first_line_indent: buffer
 6614                        .indent_size_for_line(MultiBufferRow(selection.start.row))
 6615                        .len,
 6616                });
 6617            }
 6618        }
 6619
 6620        self.transact(cx, |this, cx| {
 6621            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6622                s.select(selections);
 6623            });
 6624            this.insert("", cx);
 6625            cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
 6626                text,
 6627                clipboard_selections,
 6628            ));
 6629        });
 6630    }
 6631
 6632    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
 6633        let selections = self.selections.all::<Point>(cx);
 6634        let buffer = self.buffer.read(cx).read(cx);
 6635        let mut text = String::new();
 6636
 6637        let mut clipboard_selections = Vec::with_capacity(selections.len());
 6638        {
 6639            let max_point = buffer.max_point();
 6640            let mut is_first = true;
 6641            for selection in selections.iter() {
 6642                let mut start = selection.start;
 6643                let mut end = selection.end;
 6644                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 6645                if is_entire_line {
 6646                    start = Point::new(start.row, 0);
 6647                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 6648                }
 6649                if is_first {
 6650                    is_first = false;
 6651                } else {
 6652                    text += "\n";
 6653                }
 6654                let mut len = 0;
 6655                for chunk in buffer.text_for_range(start..end) {
 6656                    text.push_str(chunk);
 6657                    len += chunk.len();
 6658                }
 6659                clipboard_selections.push(ClipboardSelection {
 6660                    len,
 6661                    is_entire_line,
 6662                    first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
 6663                });
 6664            }
 6665        }
 6666
 6667        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
 6668            text,
 6669            clipboard_selections,
 6670        ));
 6671    }
 6672
 6673    pub fn do_paste(
 6674        &mut self,
 6675        text: &String,
 6676        clipboard_selections: Option<Vec<ClipboardSelection>>,
 6677        handle_entire_lines: bool,
 6678        cx: &mut ViewContext<Self>,
 6679    ) {
 6680        if self.read_only(cx) {
 6681            return;
 6682        }
 6683
 6684        let clipboard_text = Cow::Borrowed(text);
 6685
 6686        self.transact(cx, |this, cx| {
 6687            if let Some(mut clipboard_selections) = clipboard_selections {
 6688                let old_selections = this.selections.all::<usize>(cx);
 6689                let all_selections_were_entire_line =
 6690                    clipboard_selections.iter().all(|s| s.is_entire_line);
 6691                let first_selection_indent_column =
 6692                    clipboard_selections.first().map(|s| s.first_line_indent);
 6693                if clipboard_selections.len() != old_selections.len() {
 6694                    clipboard_selections.drain(..);
 6695                }
 6696
 6697                this.buffer.update(cx, |buffer, cx| {
 6698                    let snapshot = buffer.read(cx);
 6699                    let mut start_offset = 0;
 6700                    let mut edits = Vec::new();
 6701                    let mut original_indent_columns = Vec::new();
 6702                    for (ix, selection) in old_selections.iter().enumerate() {
 6703                        let to_insert;
 6704                        let entire_line;
 6705                        let original_indent_column;
 6706                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 6707                            let end_offset = start_offset + clipboard_selection.len;
 6708                            to_insert = &clipboard_text[start_offset..end_offset];
 6709                            entire_line = clipboard_selection.is_entire_line;
 6710                            start_offset = end_offset + 1;
 6711                            original_indent_column = Some(clipboard_selection.first_line_indent);
 6712                        } else {
 6713                            to_insert = clipboard_text.as_str();
 6714                            entire_line = all_selections_were_entire_line;
 6715                            original_indent_column = first_selection_indent_column
 6716                        }
 6717
 6718                        // If the corresponding selection was empty when this slice of the
 6719                        // clipboard text was written, then the entire line containing the
 6720                        // selection was copied. If this selection is also currently empty,
 6721                        // then paste the line before the current line of the buffer.
 6722                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
 6723                            let column = selection.start.to_point(&snapshot).column as usize;
 6724                            let line_start = selection.start - column;
 6725                            line_start..line_start
 6726                        } else {
 6727                            selection.range()
 6728                        };
 6729
 6730                        edits.push((range, to_insert));
 6731                        original_indent_columns.extend(original_indent_column);
 6732                    }
 6733                    drop(snapshot);
 6734
 6735                    buffer.edit(
 6736                        edits,
 6737                        Some(AutoindentMode::Block {
 6738                            original_indent_columns,
 6739                        }),
 6740                        cx,
 6741                    );
 6742                });
 6743
 6744                let selections = this.selections.all::<usize>(cx);
 6745                this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6746            } else {
 6747                this.insert(&clipboard_text, cx);
 6748            }
 6749        });
 6750    }
 6751
 6752    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
 6753        if let Some(item) = cx.read_from_clipboard() {
 6754            let entries = item.entries();
 6755
 6756            match entries.first() {
 6757                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
 6758                // of all the pasted entries.
 6759                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
 6760                    .do_paste(
 6761                        clipboard_string.text(),
 6762                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
 6763                        true,
 6764                        cx,
 6765                    ),
 6766                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, cx),
 6767            }
 6768        }
 6769    }
 6770
 6771    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
 6772        if self.read_only(cx) {
 6773            return;
 6774        }
 6775
 6776        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 6777            if let Some((selections, _)) =
 6778                self.selection_history.transaction(transaction_id).cloned()
 6779            {
 6780                self.change_selections(None, cx, |s| {
 6781                    s.select_anchors(selections.to_vec());
 6782                });
 6783            }
 6784            self.request_autoscroll(Autoscroll::fit(), cx);
 6785            self.unmark_text(cx);
 6786            self.refresh_inline_completion(true, cx);
 6787            cx.emit(EditorEvent::Edited { transaction_id });
 6788            cx.emit(EditorEvent::TransactionUndone { transaction_id });
 6789        }
 6790    }
 6791
 6792    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 6793        if self.read_only(cx) {
 6794            return;
 6795        }
 6796
 6797        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 6798            if let Some((_, Some(selections))) =
 6799                self.selection_history.transaction(transaction_id).cloned()
 6800            {
 6801                self.change_selections(None, cx, |s| {
 6802                    s.select_anchors(selections.to_vec());
 6803                });
 6804            }
 6805            self.request_autoscroll(Autoscroll::fit(), cx);
 6806            self.unmark_text(cx);
 6807            self.refresh_inline_completion(true, cx);
 6808            cx.emit(EditorEvent::Edited { transaction_id });
 6809        }
 6810    }
 6811
 6812    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 6813        self.buffer
 6814            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 6815    }
 6816
 6817    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut ViewContext<Self>) {
 6818        self.buffer
 6819            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
 6820    }
 6821
 6822    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 6823        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6824            let line_mode = s.line_mode;
 6825            s.move_with(|map, selection| {
 6826                let cursor = if selection.is_empty() && !line_mode {
 6827                    movement::left(map, selection.start)
 6828                } else {
 6829                    selection.start
 6830                };
 6831                selection.collapse_to(cursor, SelectionGoal::None);
 6832            });
 6833        })
 6834    }
 6835
 6836    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 6837        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6838            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 6839        })
 6840    }
 6841
 6842    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 6843        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6844            let line_mode = s.line_mode;
 6845            s.move_with(|map, selection| {
 6846                let cursor = if selection.is_empty() && !line_mode {
 6847                    movement::right(map, selection.end)
 6848                } else {
 6849                    selection.end
 6850                };
 6851                selection.collapse_to(cursor, SelectionGoal::None)
 6852            });
 6853        })
 6854    }
 6855
 6856    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 6857        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6858            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 6859        })
 6860    }
 6861
 6862    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 6863        if self.take_rename(true, cx).is_some() {
 6864            return;
 6865        }
 6866
 6867        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6868            cx.propagate();
 6869            return;
 6870        }
 6871
 6872        let text_layout_details = &self.text_layout_details(cx);
 6873        let selection_count = self.selections.count();
 6874        let first_selection = self.selections.first_anchor();
 6875
 6876        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6877            let line_mode = s.line_mode;
 6878            s.move_with(|map, selection| {
 6879                if !selection.is_empty() && !line_mode {
 6880                    selection.goal = SelectionGoal::None;
 6881                }
 6882                let (cursor, goal) = movement::up(
 6883                    map,
 6884                    selection.start,
 6885                    selection.goal,
 6886                    false,
 6887                    &text_layout_details,
 6888                );
 6889                selection.collapse_to(cursor, goal);
 6890            });
 6891        });
 6892
 6893        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 6894        {
 6895            cx.propagate();
 6896        }
 6897    }
 6898
 6899    pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
 6900        if self.take_rename(true, cx).is_some() {
 6901            return;
 6902        }
 6903
 6904        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6905            cx.propagate();
 6906            return;
 6907        }
 6908
 6909        let text_layout_details = &self.text_layout_details(cx);
 6910
 6911        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6912            let line_mode = s.line_mode;
 6913            s.move_with(|map, selection| {
 6914                if !selection.is_empty() && !line_mode {
 6915                    selection.goal = SelectionGoal::None;
 6916                }
 6917                let (cursor, goal) = movement::up_by_rows(
 6918                    map,
 6919                    selection.start,
 6920                    action.lines,
 6921                    selection.goal,
 6922                    false,
 6923                    &text_layout_details,
 6924                );
 6925                selection.collapse_to(cursor, goal);
 6926            });
 6927        })
 6928    }
 6929
 6930    pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext<Self>) {
 6931        if self.take_rename(true, cx).is_some() {
 6932            return;
 6933        }
 6934
 6935        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6936            cx.propagate();
 6937            return;
 6938        }
 6939
 6940        let text_layout_details = &self.text_layout_details(cx);
 6941
 6942        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6943            let line_mode = s.line_mode;
 6944            s.move_with(|map, selection| {
 6945                if !selection.is_empty() && !line_mode {
 6946                    selection.goal = SelectionGoal::None;
 6947                }
 6948                let (cursor, goal) = movement::down_by_rows(
 6949                    map,
 6950                    selection.start,
 6951                    action.lines,
 6952                    selection.goal,
 6953                    false,
 6954                    &text_layout_details,
 6955                );
 6956                selection.collapse_to(cursor, goal);
 6957            });
 6958        })
 6959    }
 6960
 6961    pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext<Self>) {
 6962        let text_layout_details = &self.text_layout_details(cx);
 6963        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6964            s.move_heads_with(|map, head, goal| {
 6965                movement::down_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 6966            })
 6967        })
 6968    }
 6969
 6970    pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext<Self>) {
 6971        let text_layout_details = &self.text_layout_details(cx);
 6972        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6973            s.move_heads_with(|map, head, goal| {
 6974                movement::up_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 6975            })
 6976        })
 6977    }
 6978
 6979    pub fn select_page_up(&mut self, _: &SelectPageUp, cx: &mut ViewContext<Self>) {
 6980        let Some(row_count) = self.visible_row_count() else {
 6981            return;
 6982        };
 6983
 6984        let text_layout_details = &self.text_layout_details(cx);
 6985
 6986        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6987            s.move_heads_with(|map, head, goal| {
 6988                movement::up_by_rows(map, head, row_count, goal, false, &text_layout_details)
 6989            })
 6990        })
 6991    }
 6992
 6993    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
 6994        if self.take_rename(true, cx).is_some() {
 6995            return;
 6996        }
 6997
 6998        if self
 6999            .context_menu
 7000            .write()
 7001            .as_mut()
 7002            .map(|menu| menu.select_first(self.project.as_ref(), cx))
 7003            .unwrap_or(false)
 7004        {
 7005            return;
 7006        }
 7007
 7008        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7009            cx.propagate();
 7010            return;
 7011        }
 7012
 7013        let Some(row_count) = self.visible_row_count() else {
 7014            return;
 7015        };
 7016
 7017        let autoscroll = if action.center_cursor {
 7018            Autoscroll::center()
 7019        } else {
 7020            Autoscroll::fit()
 7021        };
 7022
 7023        let text_layout_details = &self.text_layout_details(cx);
 7024
 7025        self.change_selections(Some(autoscroll), cx, |s| {
 7026            let line_mode = s.line_mode;
 7027            s.move_with(|map, selection| {
 7028                if !selection.is_empty() && !line_mode {
 7029                    selection.goal = SelectionGoal::None;
 7030                }
 7031                let (cursor, goal) = movement::up_by_rows(
 7032                    map,
 7033                    selection.end,
 7034                    row_count,
 7035                    selection.goal,
 7036                    false,
 7037                    &text_layout_details,
 7038                );
 7039                selection.collapse_to(cursor, goal);
 7040            });
 7041        });
 7042    }
 7043
 7044    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 7045        let text_layout_details = &self.text_layout_details(cx);
 7046        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7047            s.move_heads_with(|map, head, goal| {
 7048                movement::up(map, head, goal, false, &text_layout_details)
 7049            })
 7050        })
 7051    }
 7052
 7053    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 7054        self.take_rename(true, cx);
 7055
 7056        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7057            cx.propagate();
 7058            return;
 7059        }
 7060
 7061        let text_layout_details = &self.text_layout_details(cx);
 7062        let selection_count = self.selections.count();
 7063        let first_selection = self.selections.first_anchor();
 7064
 7065        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7066            let line_mode = s.line_mode;
 7067            s.move_with(|map, selection| {
 7068                if !selection.is_empty() && !line_mode {
 7069                    selection.goal = SelectionGoal::None;
 7070                }
 7071                let (cursor, goal) = movement::down(
 7072                    map,
 7073                    selection.end,
 7074                    selection.goal,
 7075                    false,
 7076                    &text_layout_details,
 7077                );
 7078                selection.collapse_to(cursor, goal);
 7079            });
 7080        });
 7081
 7082        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 7083        {
 7084            cx.propagate();
 7085        }
 7086    }
 7087
 7088    pub fn select_page_down(&mut self, _: &SelectPageDown, cx: &mut ViewContext<Self>) {
 7089        let Some(row_count) = self.visible_row_count() else {
 7090            return;
 7091        };
 7092
 7093        let text_layout_details = &self.text_layout_details(cx);
 7094
 7095        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7096            s.move_heads_with(|map, head, goal| {
 7097                movement::down_by_rows(map, head, row_count, goal, false, &text_layout_details)
 7098            })
 7099        })
 7100    }
 7101
 7102    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
 7103        if self.take_rename(true, cx).is_some() {
 7104            return;
 7105        }
 7106
 7107        if self
 7108            .context_menu
 7109            .write()
 7110            .as_mut()
 7111            .map(|menu| menu.select_last(self.project.as_ref(), cx))
 7112            .unwrap_or(false)
 7113        {
 7114            return;
 7115        }
 7116
 7117        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7118            cx.propagate();
 7119            return;
 7120        }
 7121
 7122        let Some(row_count) = self.visible_row_count() else {
 7123            return;
 7124        };
 7125
 7126        let autoscroll = if action.center_cursor {
 7127            Autoscroll::center()
 7128        } else {
 7129            Autoscroll::fit()
 7130        };
 7131
 7132        let text_layout_details = &self.text_layout_details(cx);
 7133        self.change_selections(Some(autoscroll), cx, |s| {
 7134            let line_mode = s.line_mode;
 7135            s.move_with(|map, selection| {
 7136                if !selection.is_empty() && !line_mode {
 7137                    selection.goal = SelectionGoal::None;
 7138                }
 7139                let (cursor, goal) = movement::down_by_rows(
 7140                    map,
 7141                    selection.end,
 7142                    row_count,
 7143                    selection.goal,
 7144                    false,
 7145                    &text_layout_details,
 7146                );
 7147                selection.collapse_to(cursor, goal);
 7148            });
 7149        });
 7150    }
 7151
 7152    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 7153        let text_layout_details = &self.text_layout_details(cx);
 7154        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7155            s.move_heads_with(|map, head, goal| {
 7156                movement::down(map, head, goal, false, &text_layout_details)
 7157            })
 7158        });
 7159    }
 7160
 7161    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
 7162        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7163            context_menu.select_first(self.project.as_ref(), cx);
 7164        }
 7165    }
 7166
 7167    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
 7168        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7169            context_menu.select_prev(self.project.as_ref(), cx);
 7170        }
 7171    }
 7172
 7173    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
 7174        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7175            context_menu.select_next(self.project.as_ref(), cx);
 7176        }
 7177    }
 7178
 7179    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
 7180        if let Some(context_menu) = self.context_menu.write().as_mut() {
 7181            context_menu.select_last(self.project.as_ref(), cx);
 7182        }
 7183    }
 7184
 7185    pub fn move_to_previous_word_start(
 7186        &mut self,
 7187        _: &MoveToPreviousWordStart,
 7188        cx: &mut ViewContext<Self>,
 7189    ) {
 7190        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7191            s.move_cursors_with(|map, head, _| {
 7192                (
 7193                    movement::previous_word_start(map, head),
 7194                    SelectionGoal::None,
 7195                )
 7196            });
 7197        })
 7198    }
 7199
 7200    pub fn move_to_previous_subword_start(
 7201        &mut self,
 7202        _: &MoveToPreviousSubwordStart,
 7203        cx: &mut ViewContext<Self>,
 7204    ) {
 7205        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7206            s.move_cursors_with(|map, head, _| {
 7207                (
 7208                    movement::previous_subword_start(map, head),
 7209                    SelectionGoal::None,
 7210                )
 7211            });
 7212        })
 7213    }
 7214
 7215    pub fn select_to_previous_word_start(
 7216        &mut self,
 7217        _: &SelectToPreviousWordStart,
 7218        cx: &mut ViewContext<Self>,
 7219    ) {
 7220        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7221            s.move_heads_with(|map, head, _| {
 7222                (
 7223                    movement::previous_word_start(map, head),
 7224                    SelectionGoal::None,
 7225                )
 7226            });
 7227        })
 7228    }
 7229
 7230    pub fn select_to_previous_subword_start(
 7231        &mut self,
 7232        _: &SelectToPreviousSubwordStart,
 7233        cx: &mut ViewContext<Self>,
 7234    ) {
 7235        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7236            s.move_heads_with(|map, head, _| {
 7237                (
 7238                    movement::previous_subword_start(map, head),
 7239                    SelectionGoal::None,
 7240                )
 7241            });
 7242        })
 7243    }
 7244
 7245    pub fn delete_to_previous_word_start(
 7246        &mut self,
 7247        _: &DeleteToPreviousWordStart,
 7248        cx: &mut ViewContext<Self>,
 7249    ) {
 7250        self.transact(cx, |this, cx| {
 7251            this.select_autoclose_pair(cx);
 7252            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7253                let line_mode = s.line_mode;
 7254                s.move_with(|map, selection| {
 7255                    if selection.is_empty() && !line_mode {
 7256                        let cursor = movement::previous_word_start(map, selection.head());
 7257                        selection.set_head(cursor, SelectionGoal::None);
 7258                    }
 7259                });
 7260            });
 7261            this.insert("", cx);
 7262        });
 7263    }
 7264
 7265    pub fn delete_to_previous_subword_start(
 7266        &mut self,
 7267        _: &DeleteToPreviousSubwordStart,
 7268        cx: &mut ViewContext<Self>,
 7269    ) {
 7270        self.transact(cx, |this, cx| {
 7271            this.select_autoclose_pair(cx);
 7272            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7273                let line_mode = s.line_mode;
 7274                s.move_with(|map, selection| {
 7275                    if selection.is_empty() && !line_mode {
 7276                        let cursor = movement::previous_subword_start(map, selection.head());
 7277                        selection.set_head(cursor, SelectionGoal::None);
 7278                    }
 7279                });
 7280            });
 7281            this.insert("", cx);
 7282        });
 7283    }
 7284
 7285    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 7286        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7287            s.move_cursors_with(|map, head, _| {
 7288                (movement::next_word_end(map, head), SelectionGoal::None)
 7289            });
 7290        })
 7291    }
 7292
 7293    pub fn move_to_next_subword_end(
 7294        &mut self,
 7295        _: &MoveToNextSubwordEnd,
 7296        cx: &mut ViewContext<Self>,
 7297    ) {
 7298        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7299            s.move_cursors_with(|map, head, _| {
 7300                (movement::next_subword_end(map, head), SelectionGoal::None)
 7301            });
 7302        })
 7303    }
 7304
 7305    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 7306        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7307            s.move_heads_with(|map, head, _| {
 7308                (movement::next_word_end(map, head), SelectionGoal::None)
 7309            });
 7310        })
 7311    }
 7312
 7313    pub fn select_to_next_subword_end(
 7314        &mut self,
 7315        _: &SelectToNextSubwordEnd,
 7316        cx: &mut ViewContext<Self>,
 7317    ) {
 7318        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7319            s.move_heads_with(|map, head, _| {
 7320                (movement::next_subword_end(map, head), SelectionGoal::None)
 7321            });
 7322        })
 7323    }
 7324
 7325    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
 7326        self.transact(cx, |this, cx| {
 7327            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7328                let line_mode = s.line_mode;
 7329                s.move_with(|map, selection| {
 7330                    if selection.is_empty() && !line_mode {
 7331                        let cursor = movement::next_word_end(map, selection.head());
 7332                        selection.set_head(cursor, SelectionGoal::None);
 7333                    }
 7334                });
 7335            });
 7336            this.insert("", cx);
 7337        });
 7338    }
 7339
 7340    pub fn delete_to_next_subword_end(
 7341        &mut self,
 7342        _: &DeleteToNextSubwordEnd,
 7343        cx: &mut ViewContext<Self>,
 7344    ) {
 7345        self.transact(cx, |this, cx| {
 7346            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7347                s.move_with(|map, selection| {
 7348                    if selection.is_empty() {
 7349                        let cursor = movement::next_subword_end(map, selection.head());
 7350                        selection.set_head(cursor, SelectionGoal::None);
 7351                    }
 7352                });
 7353            });
 7354            this.insert("", cx);
 7355        });
 7356    }
 7357
 7358    pub fn move_to_beginning_of_line(
 7359        &mut self,
 7360        action: &MoveToBeginningOfLine,
 7361        cx: &mut ViewContext<Self>,
 7362    ) {
 7363        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7364            s.move_cursors_with(|map, head, _| {
 7365                (
 7366                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 7367                    SelectionGoal::None,
 7368                )
 7369            });
 7370        })
 7371    }
 7372
 7373    pub fn select_to_beginning_of_line(
 7374        &mut self,
 7375        action: &SelectToBeginningOfLine,
 7376        cx: &mut ViewContext<Self>,
 7377    ) {
 7378        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7379            s.move_heads_with(|map, head, _| {
 7380                (
 7381                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 7382                    SelectionGoal::None,
 7383                )
 7384            });
 7385        });
 7386    }
 7387
 7388    pub fn delete_to_beginning_of_line(
 7389        &mut self,
 7390        _: &DeleteToBeginningOfLine,
 7391        cx: &mut ViewContext<Self>,
 7392    ) {
 7393        self.transact(cx, |this, cx| {
 7394            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7395                s.move_with(|_, selection| {
 7396                    selection.reversed = true;
 7397                });
 7398            });
 7399
 7400            this.select_to_beginning_of_line(
 7401                &SelectToBeginningOfLine {
 7402                    stop_at_soft_wraps: false,
 7403                },
 7404                cx,
 7405            );
 7406            this.backspace(&Backspace, cx);
 7407        });
 7408    }
 7409
 7410    pub fn move_to_end_of_line(&mut self, action: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 7411        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7412            s.move_cursors_with(|map, head, _| {
 7413                (
 7414                    movement::line_end(map, head, action.stop_at_soft_wraps),
 7415                    SelectionGoal::None,
 7416                )
 7417            });
 7418        })
 7419    }
 7420
 7421    pub fn select_to_end_of_line(
 7422        &mut self,
 7423        action: &SelectToEndOfLine,
 7424        cx: &mut ViewContext<Self>,
 7425    ) {
 7426        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7427            s.move_heads_with(|map, head, _| {
 7428                (
 7429                    movement::line_end(map, head, action.stop_at_soft_wraps),
 7430                    SelectionGoal::None,
 7431                )
 7432            });
 7433        })
 7434    }
 7435
 7436    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 7437        self.transact(cx, |this, cx| {
 7438            this.select_to_end_of_line(
 7439                &SelectToEndOfLine {
 7440                    stop_at_soft_wraps: false,
 7441                },
 7442                cx,
 7443            );
 7444            this.delete(&Delete, cx);
 7445        });
 7446    }
 7447
 7448    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 7449        self.transact(cx, |this, cx| {
 7450            this.select_to_end_of_line(
 7451                &SelectToEndOfLine {
 7452                    stop_at_soft_wraps: false,
 7453                },
 7454                cx,
 7455            );
 7456            this.cut(&Cut, cx);
 7457        });
 7458    }
 7459
 7460    pub fn move_to_start_of_paragraph(
 7461        &mut self,
 7462        _: &MoveToStartOfParagraph,
 7463        cx: &mut ViewContext<Self>,
 7464    ) {
 7465        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7466            cx.propagate();
 7467            return;
 7468        }
 7469
 7470        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7471            s.move_with(|map, selection| {
 7472                selection.collapse_to(
 7473                    movement::start_of_paragraph(map, selection.head(), 1),
 7474                    SelectionGoal::None,
 7475                )
 7476            });
 7477        })
 7478    }
 7479
 7480    pub fn move_to_end_of_paragraph(
 7481        &mut self,
 7482        _: &MoveToEndOfParagraph,
 7483        cx: &mut ViewContext<Self>,
 7484    ) {
 7485        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7486            cx.propagate();
 7487            return;
 7488        }
 7489
 7490        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7491            s.move_with(|map, selection| {
 7492                selection.collapse_to(
 7493                    movement::end_of_paragraph(map, selection.head(), 1),
 7494                    SelectionGoal::None,
 7495                )
 7496            });
 7497        })
 7498    }
 7499
 7500    pub fn select_to_start_of_paragraph(
 7501        &mut self,
 7502        _: &SelectToStartOfParagraph,
 7503        cx: &mut ViewContext<Self>,
 7504    ) {
 7505        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7506            cx.propagate();
 7507            return;
 7508        }
 7509
 7510        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7511            s.move_heads_with(|map, head, _| {
 7512                (
 7513                    movement::start_of_paragraph(map, head, 1),
 7514                    SelectionGoal::None,
 7515                )
 7516            });
 7517        })
 7518    }
 7519
 7520    pub fn select_to_end_of_paragraph(
 7521        &mut self,
 7522        _: &SelectToEndOfParagraph,
 7523        cx: &mut ViewContext<Self>,
 7524    ) {
 7525        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7526            cx.propagate();
 7527            return;
 7528        }
 7529
 7530        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7531            s.move_heads_with(|map, head, _| {
 7532                (
 7533                    movement::end_of_paragraph(map, head, 1),
 7534                    SelectionGoal::None,
 7535                )
 7536            });
 7537        })
 7538    }
 7539
 7540    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 7541        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7542            cx.propagate();
 7543            return;
 7544        }
 7545
 7546        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7547            s.select_ranges(vec![0..0]);
 7548        });
 7549    }
 7550
 7551    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 7552        let mut selection = self.selections.last::<Point>(cx);
 7553        selection.set_head(Point::zero(), SelectionGoal::None);
 7554
 7555        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7556            s.select(vec![selection]);
 7557        });
 7558    }
 7559
 7560    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 7561        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 7562            cx.propagate();
 7563            return;
 7564        }
 7565
 7566        let cursor = self.buffer.read(cx).read(cx).len();
 7567        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7568            s.select_ranges(vec![cursor..cursor])
 7569        });
 7570    }
 7571
 7572    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 7573        self.nav_history = nav_history;
 7574    }
 7575
 7576    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 7577        self.nav_history.as_ref()
 7578    }
 7579
 7580    fn push_to_nav_history(
 7581        &mut self,
 7582        cursor_anchor: Anchor,
 7583        new_position: Option<Point>,
 7584        cx: &mut ViewContext<Self>,
 7585    ) {
 7586        if let Some(nav_history) = self.nav_history.as_mut() {
 7587            let buffer = self.buffer.read(cx).read(cx);
 7588            let cursor_position = cursor_anchor.to_point(&buffer);
 7589            let scroll_state = self.scroll_manager.anchor();
 7590            let scroll_top_row = scroll_state.top_row(&buffer);
 7591            drop(buffer);
 7592
 7593            if let Some(new_position) = new_position {
 7594                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 7595                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 7596                    return;
 7597                }
 7598            }
 7599
 7600            nav_history.push(
 7601                Some(NavigationData {
 7602                    cursor_anchor,
 7603                    cursor_position,
 7604                    scroll_anchor: scroll_state,
 7605                    scroll_top_row,
 7606                }),
 7607                cx,
 7608            );
 7609        }
 7610    }
 7611
 7612    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 7613        let buffer = self.buffer.read(cx).snapshot(cx);
 7614        let mut selection = self.selections.first::<usize>(cx);
 7615        selection.set_head(buffer.len(), SelectionGoal::None);
 7616        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7617            s.select(vec![selection]);
 7618        });
 7619    }
 7620
 7621    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 7622        let end = self.buffer.read(cx).read(cx).len();
 7623        self.change_selections(None, cx, |s| {
 7624            s.select_ranges(vec![0..end]);
 7625        });
 7626    }
 7627
 7628    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 7629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7630        let mut selections = self.selections.all::<Point>(cx);
 7631        let max_point = display_map.buffer_snapshot.max_point();
 7632        for selection in &mut selections {
 7633            let rows = selection.spanned_rows(true, &display_map);
 7634            selection.start = Point::new(rows.start.0, 0);
 7635            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
 7636            selection.reversed = false;
 7637        }
 7638        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7639            s.select(selections);
 7640        });
 7641    }
 7642
 7643    pub fn split_selection_into_lines(
 7644        &mut self,
 7645        _: &SplitSelectionIntoLines,
 7646        cx: &mut ViewContext<Self>,
 7647    ) {
 7648        let mut to_unfold = Vec::new();
 7649        let mut new_selection_ranges = Vec::new();
 7650        {
 7651            let selections = self.selections.all::<Point>(cx);
 7652            let buffer = self.buffer.read(cx).read(cx);
 7653            for selection in selections {
 7654                for row in selection.start.row..selection.end.row {
 7655                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
 7656                    new_selection_ranges.push(cursor..cursor);
 7657                }
 7658                new_selection_ranges.push(selection.end..selection.end);
 7659                to_unfold.push(selection.start..selection.end);
 7660            }
 7661        }
 7662        self.unfold_ranges(to_unfold, true, true, cx);
 7663        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7664            s.select_ranges(new_selection_ranges);
 7665        });
 7666    }
 7667
 7668    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 7669        self.add_selection(true, cx);
 7670    }
 7671
 7672    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 7673        self.add_selection(false, cx);
 7674    }
 7675
 7676    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 7677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7678        let mut selections = self.selections.all::<Point>(cx);
 7679        let text_layout_details = self.text_layout_details(cx);
 7680        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 7681            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 7682            let range = oldest_selection.display_range(&display_map).sorted();
 7683
 7684            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 7685            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 7686            let positions = start_x.min(end_x)..start_x.max(end_x);
 7687
 7688            selections.clear();
 7689            let mut stack = Vec::new();
 7690            for row in range.start.row().0..=range.end.row().0 {
 7691                if let Some(selection) = self.selections.build_columnar_selection(
 7692                    &display_map,
 7693                    DisplayRow(row),
 7694                    &positions,
 7695                    oldest_selection.reversed,
 7696                    &text_layout_details,
 7697                ) {
 7698                    stack.push(selection.id);
 7699                    selections.push(selection);
 7700                }
 7701            }
 7702
 7703            if above {
 7704                stack.reverse();
 7705            }
 7706
 7707            AddSelectionsState { above, stack }
 7708        });
 7709
 7710        let last_added_selection = *state.stack.last().unwrap();
 7711        let mut new_selections = Vec::new();
 7712        if above == state.above {
 7713            let end_row = if above {
 7714                DisplayRow(0)
 7715            } else {
 7716                display_map.max_point().row()
 7717            };
 7718
 7719            'outer: for selection in selections {
 7720                if selection.id == last_added_selection {
 7721                    let range = selection.display_range(&display_map).sorted();
 7722                    debug_assert_eq!(range.start.row(), range.end.row());
 7723                    let mut row = range.start.row();
 7724                    let positions =
 7725                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 7726                            px(start)..px(end)
 7727                        } else {
 7728                            let start_x =
 7729                                display_map.x_for_display_point(range.start, &text_layout_details);
 7730                            let end_x =
 7731                                display_map.x_for_display_point(range.end, &text_layout_details);
 7732                            start_x.min(end_x)..start_x.max(end_x)
 7733                        };
 7734
 7735                    while row != end_row {
 7736                        if above {
 7737                            row.0 -= 1;
 7738                        } else {
 7739                            row.0 += 1;
 7740                        }
 7741
 7742                        if let Some(new_selection) = self.selections.build_columnar_selection(
 7743                            &display_map,
 7744                            row,
 7745                            &positions,
 7746                            selection.reversed,
 7747                            &text_layout_details,
 7748                        ) {
 7749                            state.stack.push(new_selection.id);
 7750                            if above {
 7751                                new_selections.push(new_selection);
 7752                                new_selections.push(selection);
 7753                            } else {
 7754                                new_selections.push(selection);
 7755                                new_selections.push(new_selection);
 7756                            }
 7757
 7758                            continue 'outer;
 7759                        }
 7760                    }
 7761                }
 7762
 7763                new_selections.push(selection);
 7764            }
 7765        } else {
 7766            new_selections = selections;
 7767            new_selections.retain(|s| s.id != last_added_selection);
 7768            state.stack.pop();
 7769        }
 7770
 7771        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7772            s.select(new_selections);
 7773        });
 7774        if state.stack.len() > 1 {
 7775            self.add_selections_state = Some(state);
 7776        }
 7777    }
 7778
 7779    pub fn select_next_match_internal(
 7780        &mut self,
 7781        display_map: &DisplaySnapshot,
 7782        replace_newest: bool,
 7783        autoscroll: Option<Autoscroll>,
 7784        cx: &mut ViewContext<Self>,
 7785    ) -> Result<()> {
 7786        fn select_next_match_ranges(
 7787            this: &mut Editor,
 7788            range: Range<usize>,
 7789            replace_newest: bool,
 7790            auto_scroll: Option<Autoscroll>,
 7791            cx: &mut ViewContext<Editor>,
 7792        ) {
 7793            this.unfold_ranges([range.clone()], false, true, cx);
 7794            this.change_selections(auto_scroll, cx, |s| {
 7795                if replace_newest {
 7796                    s.delete(s.newest_anchor().id);
 7797                }
 7798                s.insert_range(range.clone());
 7799            });
 7800        }
 7801
 7802        let buffer = &display_map.buffer_snapshot;
 7803        let mut selections = self.selections.all::<usize>(cx);
 7804        if let Some(mut select_next_state) = self.select_next_state.take() {
 7805            let query = &select_next_state.query;
 7806            if !select_next_state.done {
 7807                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 7808                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 7809                let mut next_selected_range = None;
 7810
 7811                let bytes_after_last_selection =
 7812                    buffer.bytes_in_range(last_selection.end..buffer.len());
 7813                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 7814                let query_matches = query
 7815                    .stream_find_iter(bytes_after_last_selection)
 7816                    .map(|result| (last_selection.end, result))
 7817                    .chain(
 7818                        query
 7819                            .stream_find_iter(bytes_before_first_selection)
 7820                            .map(|result| (0, result)),
 7821                    );
 7822
 7823                for (start_offset, query_match) in query_matches {
 7824                    let query_match = query_match.unwrap(); // can only fail due to I/O
 7825                    let offset_range =
 7826                        start_offset + query_match.start()..start_offset + query_match.end();
 7827                    let display_range = offset_range.start.to_display_point(&display_map)
 7828                        ..offset_range.end.to_display_point(&display_map);
 7829
 7830                    if !select_next_state.wordwise
 7831                        || (!movement::is_inside_word(&display_map, display_range.start)
 7832                            && !movement::is_inside_word(&display_map, display_range.end))
 7833                    {
 7834                        // TODO: This is n^2, because we might check all the selections
 7835                        if !selections
 7836                            .iter()
 7837                            .any(|selection| selection.range().overlaps(&offset_range))
 7838                        {
 7839                            next_selected_range = Some(offset_range);
 7840                            break;
 7841                        }
 7842                    }
 7843                }
 7844
 7845                if let Some(next_selected_range) = next_selected_range {
 7846                    select_next_match_ranges(
 7847                        self,
 7848                        next_selected_range,
 7849                        replace_newest,
 7850                        autoscroll,
 7851                        cx,
 7852                    );
 7853                } else {
 7854                    select_next_state.done = true;
 7855                }
 7856            }
 7857
 7858            self.select_next_state = Some(select_next_state);
 7859        } else {
 7860            let mut only_carets = true;
 7861            let mut same_text_selected = true;
 7862            let mut selected_text = None;
 7863
 7864            let mut selections_iter = selections.iter().peekable();
 7865            while let Some(selection) = selections_iter.next() {
 7866                if selection.start != selection.end {
 7867                    only_carets = false;
 7868                }
 7869
 7870                if same_text_selected {
 7871                    if selected_text.is_none() {
 7872                        selected_text =
 7873                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 7874                    }
 7875
 7876                    if let Some(next_selection) = selections_iter.peek() {
 7877                        if next_selection.range().len() == selection.range().len() {
 7878                            let next_selected_text = buffer
 7879                                .text_for_range(next_selection.range())
 7880                                .collect::<String>();
 7881                            if Some(next_selected_text) != selected_text {
 7882                                same_text_selected = false;
 7883                                selected_text = None;
 7884                            }
 7885                        } else {
 7886                            same_text_selected = false;
 7887                            selected_text = None;
 7888                        }
 7889                    }
 7890                }
 7891            }
 7892
 7893            if only_carets {
 7894                for selection in &mut selections {
 7895                    let word_range = movement::surrounding_word(
 7896                        &display_map,
 7897                        selection.start.to_display_point(&display_map),
 7898                    );
 7899                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 7900                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 7901                    selection.goal = SelectionGoal::None;
 7902                    selection.reversed = false;
 7903                    select_next_match_ranges(
 7904                        self,
 7905                        selection.start..selection.end,
 7906                        replace_newest,
 7907                        autoscroll,
 7908                        cx,
 7909                    );
 7910                }
 7911
 7912                if selections.len() == 1 {
 7913                    let selection = selections
 7914                        .last()
 7915                        .expect("ensured that there's only one selection");
 7916                    let query = buffer
 7917                        .text_for_range(selection.start..selection.end)
 7918                        .collect::<String>();
 7919                    let is_empty = query.is_empty();
 7920                    let select_state = SelectNextState {
 7921                        query: AhoCorasick::new(&[query])?,
 7922                        wordwise: true,
 7923                        done: is_empty,
 7924                    };
 7925                    self.select_next_state = Some(select_state);
 7926                } else {
 7927                    self.select_next_state = None;
 7928                }
 7929            } else if let Some(selected_text) = selected_text {
 7930                self.select_next_state = Some(SelectNextState {
 7931                    query: AhoCorasick::new(&[selected_text])?,
 7932                    wordwise: false,
 7933                    done: false,
 7934                });
 7935                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
 7936            }
 7937        }
 7938        Ok(())
 7939    }
 7940
 7941    pub fn select_all_matches(
 7942        &mut self,
 7943        _action: &SelectAllMatches,
 7944        cx: &mut ViewContext<Self>,
 7945    ) -> Result<()> {
 7946        self.push_to_selection_history();
 7947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7948
 7949        self.select_next_match_internal(&display_map, false, None, cx)?;
 7950        let Some(select_next_state) = self.select_next_state.as_mut() else {
 7951            return Ok(());
 7952        };
 7953        if select_next_state.done {
 7954            return Ok(());
 7955        }
 7956
 7957        let mut new_selections = self.selections.all::<usize>(cx);
 7958
 7959        let buffer = &display_map.buffer_snapshot;
 7960        let query_matches = select_next_state
 7961            .query
 7962            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
 7963
 7964        for query_match in query_matches {
 7965            let query_match = query_match.unwrap(); // can only fail due to I/O
 7966            let offset_range = query_match.start()..query_match.end();
 7967            let display_range = offset_range.start.to_display_point(&display_map)
 7968                ..offset_range.end.to_display_point(&display_map);
 7969
 7970            if !select_next_state.wordwise
 7971                || (!movement::is_inside_word(&display_map, display_range.start)
 7972                    && !movement::is_inside_word(&display_map, display_range.end))
 7973            {
 7974                self.selections.change_with(cx, |selections| {
 7975                    new_selections.push(Selection {
 7976                        id: selections.new_selection_id(),
 7977                        start: offset_range.start,
 7978                        end: offset_range.end,
 7979                        reversed: false,
 7980                        goal: SelectionGoal::None,
 7981                    });
 7982                });
 7983            }
 7984        }
 7985
 7986        new_selections.sort_by_key(|selection| selection.start);
 7987        let mut ix = 0;
 7988        while ix + 1 < new_selections.len() {
 7989            let current_selection = &new_selections[ix];
 7990            let next_selection = &new_selections[ix + 1];
 7991            if current_selection.range().overlaps(&next_selection.range()) {
 7992                if current_selection.id < next_selection.id {
 7993                    new_selections.remove(ix + 1);
 7994                } else {
 7995                    new_selections.remove(ix);
 7996                }
 7997            } else {
 7998                ix += 1;
 7999            }
 8000        }
 8001
 8002        select_next_state.done = true;
 8003        self.unfold_ranges(
 8004            new_selections.iter().map(|selection| selection.range()),
 8005            false,
 8006            false,
 8007            cx,
 8008        );
 8009        self.change_selections(Some(Autoscroll::fit()), cx, |selections| {
 8010            selections.select(new_selections)
 8011        });
 8012
 8013        Ok(())
 8014    }
 8015
 8016    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
 8017        self.push_to_selection_history();
 8018        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8019        self.select_next_match_internal(
 8020            &display_map,
 8021            action.replace_newest,
 8022            Some(Autoscroll::newest()),
 8023            cx,
 8024        )?;
 8025        Ok(())
 8026    }
 8027
 8028    pub fn select_previous(
 8029        &mut self,
 8030        action: &SelectPrevious,
 8031        cx: &mut ViewContext<Self>,
 8032    ) -> Result<()> {
 8033        self.push_to_selection_history();
 8034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8035        let buffer = &display_map.buffer_snapshot;
 8036        let mut selections = self.selections.all::<usize>(cx);
 8037        if let Some(mut select_prev_state) = self.select_prev_state.take() {
 8038            let query = &select_prev_state.query;
 8039            if !select_prev_state.done {
 8040                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 8041                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 8042                let mut next_selected_range = None;
 8043                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
 8044                let bytes_before_last_selection =
 8045                    buffer.reversed_bytes_in_range(0..last_selection.start);
 8046                let bytes_after_first_selection =
 8047                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
 8048                let query_matches = query
 8049                    .stream_find_iter(bytes_before_last_selection)
 8050                    .map(|result| (last_selection.start, result))
 8051                    .chain(
 8052                        query
 8053                            .stream_find_iter(bytes_after_first_selection)
 8054                            .map(|result| (buffer.len(), result)),
 8055                    );
 8056                for (end_offset, query_match) in query_matches {
 8057                    let query_match = query_match.unwrap(); // can only fail due to I/O
 8058                    let offset_range =
 8059                        end_offset - query_match.end()..end_offset - query_match.start();
 8060                    let display_range = offset_range.start.to_display_point(&display_map)
 8061                        ..offset_range.end.to_display_point(&display_map);
 8062
 8063                    if !select_prev_state.wordwise
 8064                        || (!movement::is_inside_word(&display_map, display_range.start)
 8065                            && !movement::is_inside_word(&display_map, display_range.end))
 8066                    {
 8067                        next_selected_range = Some(offset_range);
 8068                        break;
 8069                    }
 8070                }
 8071
 8072                if let Some(next_selected_range) = next_selected_range {
 8073                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
 8074                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 8075                        if action.replace_newest {
 8076                            s.delete(s.newest_anchor().id);
 8077                        }
 8078                        s.insert_range(next_selected_range);
 8079                    });
 8080                } else {
 8081                    select_prev_state.done = true;
 8082                }
 8083            }
 8084
 8085            self.select_prev_state = Some(select_prev_state);
 8086        } else {
 8087            let mut only_carets = true;
 8088            let mut same_text_selected = true;
 8089            let mut selected_text = None;
 8090
 8091            let mut selections_iter = selections.iter().peekable();
 8092            while let Some(selection) = selections_iter.next() {
 8093                if selection.start != selection.end {
 8094                    only_carets = false;
 8095                }
 8096
 8097                if same_text_selected {
 8098                    if selected_text.is_none() {
 8099                        selected_text =
 8100                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 8101                    }
 8102
 8103                    if let Some(next_selection) = selections_iter.peek() {
 8104                        if next_selection.range().len() == selection.range().len() {
 8105                            let next_selected_text = buffer
 8106                                .text_for_range(next_selection.range())
 8107                                .collect::<String>();
 8108                            if Some(next_selected_text) != selected_text {
 8109                                same_text_selected = false;
 8110                                selected_text = None;
 8111                            }
 8112                        } else {
 8113                            same_text_selected = false;
 8114                            selected_text = None;
 8115                        }
 8116                    }
 8117                }
 8118            }
 8119
 8120            if only_carets {
 8121                for selection in &mut selections {
 8122                    let word_range = movement::surrounding_word(
 8123                        &display_map,
 8124                        selection.start.to_display_point(&display_map),
 8125                    );
 8126                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 8127                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 8128                    selection.goal = SelectionGoal::None;
 8129                    selection.reversed = false;
 8130                }
 8131                if selections.len() == 1 {
 8132                    let selection = selections
 8133                        .last()
 8134                        .expect("ensured that there's only one selection");
 8135                    let query = buffer
 8136                        .text_for_range(selection.start..selection.end)
 8137                        .collect::<String>();
 8138                    let is_empty = query.is_empty();
 8139                    let select_state = SelectNextState {
 8140                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
 8141                        wordwise: true,
 8142                        done: is_empty,
 8143                    };
 8144                    self.select_prev_state = Some(select_state);
 8145                } else {
 8146                    self.select_prev_state = None;
 8147                }
 8148
 8149                self.unfold_ranges(
 8150                    selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
 8151                    false,
 8152                    true,
 8153                    cx,
 8154                );
 8155                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 8156                    s.select(selections);
 8157                });
 8158            } else if let Some(selected_text) = selected_text {
 8159                self.select_prev_state = Some(SelectNextState {
 8160                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
 8161                    wordwise: false,
 8162                    done: false,
 8163                });
 8164                self.select_previous(action, cx)?;
 8165            }
 8166        }
 8167        Ok(())
 8168    }
 8169
 8170    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
 8171        let text_layout_details = &self.text_layout_details(cx);
 8172        self.transact(cx, |this, cx| {
 8173            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8174            let mut edits = Vec::new();
 8175            let mut selection_edit_ranges = Vec::new();
 8176            let mut last_toggled_row = None;
 8177            let snapshot = this.buffer.read(cx).read(cx);
 8178            let empty_str: Arc<str> = Arc::default();
 8179            let mut suffixes_inserted = Vec::new();
 8180
 8181            fn comment_prefix_range(
 8182                snapshot: &MultiBufferSnapshot,
 8183                row: MultiBufferRow,
 8184                comment_prefix: &str,
 8185                comment_prefix_whitespace: &str,
 8186            ) -> Range<Point> {
 8187                let start = Point::new(row.0, snapshot.indent_size_for_line(row).len);
 8188
 8189                let mut line_bytes = snapshot
 8190                    .bytes_in_range(start..snapshot.max_point())
 8191                    .flatten()
 8192                    .copied();
 8193
 8194                // If this line currently begins with the line comment prefix, then record
 8195                // the range containing the prefix.
 8196                if line_bytes
 8197                    .by_ref()
 8198                    .take(comment_prefix.len())
 8199                    .eq(comment_prefix.bytes())
 8200                {
 8201                    // Include any whitespace that matches the comment prefix.
 8202                    let matching_whitespace_len = line_bytes
 8203                        .zip(comment_prefix_whitespace.bytes())
 8204                        .take_while(|(a, b)| a == b)
 8205                        .count() as u32;
 8206                    let end = Point::new(
 8207                        start.row,
 8208                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
 8209                    );
 8210                    start..end
 8211                } else {
 8212                    start..start
 8213                }
 8214            }
 8215
 8216            fn comment_suffix_range(
 8217                snapshot: &MultiBufferSnapshot,
 8218                row: MultiBufferRow,
 8219                comment_suffix: &str,
 8220                comment_suffix_has_leading_space: bool,
 8221            ) -> Range<Point> {
 8222                let end = Point::new(row.0, snapshot.line_len(row));
 8223                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
 8224
 8225                let mut line_end_bytes = snapshot
 8226                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
 8227                    .flatten()
 8228                    .copied();
 8229
 8230                let leading_space_len = if suffix_start_column > 0
 8231                    && line_end_bytes.next() == Some(b' ')
 8232                    && comment_suffix_has_leading_space
 8233                {
 8234                    1
 8235                } else {
 8236                    0
 8237                };
 8238
 8239                // If this line currently begins with the line comment prefix, then record
 8240                // the range containing the prefix.
 8241                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
 8242                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
 8243                    start..end
 8244                } else {
 8245                    end..end
 8246                }
 8247            }
 8248
 8249            // TODO: Handle selections that cross excerpts
 8250            for selection in &mut selections {
 8251                let start_column = snapshot
 8252                    .indent_size_for_line(MultiBufferRow(selection.start.row))
 8253                    .len;
 8254                let language = if let Some(language) =
 8255                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
 8256                {
 8257                    language
 8258                } else {
 8259                    continue;
 8260                };
 8261
 8262                selection_edit_ranges.clear();
 8263
 8264                // If multiple selections contain a given row, avoid processing that
 8265                // row more than once.
 8266                let mut start_row = MultiBufferRow(selection.start.row);
 8267                if last_toggled_row == Some(start_row) {
 8268                    start_row = start_row.next_row();
 8269                }
 8270                let end_row =
 8271                    if selection.end.row > selection.start.row && selection.end.column == 0 {
 8272                        MultiBufferRow(selection.end.row - 1)
 8273                    } else {
 8274                        MultiBufferRow(selection.end.row)
 8275                    };
 8276                last_toggled_row = Some(end_row);
 8277
 8278                if start_row > end_row {
 8279                    continue;
 8280                }
 8281
 8282                // If the language has line comments, toggle those.
 8283                let full_comment_prefixes = language.line_comment_prefixes();
 8284                if !full_comment_prefixes.is_empty() {
 8285                    let first_prefix = full_comment_prefixes
 8286                        .first()
 8287                        .expect("prefixes is non-empty");
 8288                    let prefix_trimmed_lengths = full_comment_prefixes
 8289                        .iter()
 8290                        .map(|p| p.trim_end_matches(' ').len())
 8291                        .collect::<SmallVec<[usize; 4]>>();
 8292
 8293                    let mut all_selection_lines_are_comments = true;
 8294
 8295                    for row in start_row.0..=end_row.0 {
 8296                        let row = MultiBufferRow(row);
 8297                        if start_row < end_row && snapshot.is_line_blank(row) {
 8298                            continue;
 8299                        }
 8300
 8301                        let prefix_range = full_comment_prefixes
 8302                            .iter()
 8303                            .zip(prefix_trimmed_lengths.iter().copied())
 8304                            .map(|(prefix, trimmed_prefix_len)| {
 8305                                comment_prefix_range(
 8306                                    snapshot.deref(),
 8307                                    row,
 8308                                    &prefix[..trimmed_prefix_len],
 8309                                    &prefix[trimmed_prefix_len..],
 8310                                )
 8311                            })
 8312                            .max_by_key(|range| range.end.column - range.start.column)
 8313                            .expect("prefixes is non-empty");
 8314
 8315                        if prefix_range.is_empty() {
 8316                            all_selection_lines_are_comments = false;
 8317                        }
 8318
 8319                        selection_edit_ranges.push(prefix_range);
 8320                    }
 8321
 8322                    if all_selection_lines_are_comments {
 8323                        edits.extend(
 8324                            selection_edit_ranges
 8325                                .iter()
 8326                                .cloned()
 8327                                .map(|range| (range, empty_str.clone())),
 8328                        );
 8329                    } else {
 8330                        let min_column = selection_edit_ranges
 8331                            .iter()
 8332                            .map(|range| range.start.column)
 8333                            .min()
 8334                            .unwrap_or(0);
 8335                        edits.extend(selection_edit_ranges.iter().map(|range| {
 8336                            let position = Point::new(range.start.row, min_column);
 8337                            (position..position, first_prefix.clone())
 8338                        }));
 8339                    }
 8340                } else if let Some((full_comment_prefix, comment_suffix)) =
 8341                    language.block_comment_delimiters()
 8342                {
 8343                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 8344                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 8345                    let prefix_range = comment_prefix_range(
 8346                        snapshot.deref(),
 8347                        start_row,
 8348                        comment_prefix,
 8349                        comment_prefix_whitespace,
 8350                    );
 8351                    let suffix_range = comment_suffix_range(
 8352                        snapshot.deref(),
 8353                        end_row,
 8354                        comment_suffix.trim_start_matches(' '),
 8355                        comment_suffix.starts_with(' '),
 8356                    );
 8357
 8358                    if prefix_range.is_empty() || suffix_range.is_empty() {
 8359                        edits.push((
 8360                            prefix_range.start..prefix_range.start,
 8361                            full_comment_prefix.clone(),
 8362                        ));
 8363                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
 8364                        suffixes_inserted.push((end_row, comment_suffix.len()));
 8365                    } else {
 8366                        edits.push((prefix_range, empty_str.clone()));
 8367                        edits.push((suffix_range, empty_str.clone()));
 8368                    }
 8369                } else {
 8370                    continue;
 8371                }
 8372            }
 8373
 8374            drop(snapshot);
 8375            this.buffer.update(cx, |buffer, cx| {
 8376                buffer.edit(edits, None, cx);
 8377            });
 8378
 8379            // Adjust selections so that they end before any comment suffixes that
 8380            // were inserted.
 8381            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
 8382            let mut selections = this.selections.all::<Point>(cx);
 8383            let snapshot = this.buffer.read(cx).read(cx);
 8384            for selection in &mut selections {
 8385                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
 8386                    match row.cmp(&MultiBufferRow(selection.end.row)) {
 8387                        Ordering::Less => {
 8388                            suffixes_inserted.next();
 8389                            continue;
 8390                        }
 8391                        Ordering::Greater => break,
 8392                        Ordering::Equal => {
 8393                            if selection.end.column == snapshot.line_len(row) {
 8394                                if selection.is_empty() {
 8395                                    selection.start.column -= suffix_len as u32;
 8396                                }
 8397                                selection.end.column -= suffix_len as u32;
 8398                            }
 8399                            break;
 8400                        }
 8401                    }
 8402                }
 8403            }
 8404
 8405            drop(snapshot);
 8406            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 8407
 8408            let selections = this.selections.all::<Point>(cx);
 8409            let selections_on_single_row = selections.windows(2).all(|selections| {
 8410                selections[0].start.row == selections[1].start.row
 8411                    && selections[0].end.row == selections[1].end.row
 8412                    && selections[0].start.row == selections[0].end.row
 8413            });
 8414            let selections_selecting = selections
 8415                .iter()
 8416                .any(|selection| selection.start != selection.end);
 8417            let advance_downwards = action.advance_downwards
 8418                && selections_on_single_row
 8419                && !selections_selecting
 8420                && !matches!(this.mode, EditorMode::SingleLine { .. });
 8421
 8422            if advance_downwards {
 8423                let snapshot = this.buffer.read(cx).snapshot(cx);
 8424
 8425                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8426                    s.move_cursors_with(|display_snapshot, display_point, _| {
 8427                        let mut point = display_point.to_point(display_snapshot);
 8428                        point.row += 1;
 8429                        point = snapshot.clip_point(point, Bias::Left);
 8430                        let display_point = point.to_display_point(display_snapshot);
 8431                        let goal = SelectionGoal::HorizontalPosition(
 8432                            display_snapshot
 8433                                .x_for_display_point(display_point, &text_layout_details)
 8434                                .into(),
 8435                        );
 8436                        (display_point, goal)
 8437                    })
 8438                });
 8439            }
 8440        });
 8441    }
 8442
 8443    pub fn select_enclosing_symbol(
 8444        &mut self,
 8445        _: &SelectEnclosingSymbol,
 8446        cx: &mut ViewContext<Self>,
 8447    ) {
 8448        let buffer = self.buffer.read(cx).snapshot(cx);
 8449        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 8450
 8451        fn update_selection(
 8452            selection: &Selection<usize>,
 8453            buffer_snap: &MultiBufferSnapshot,
 8454        ) -> Option<Selection<usize>> {
 8455            let cursor = selection.head();
 8456            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
 8457            for symbol in symbols.iter().rev() {
 8458                let start = symbol.range.start.to_offset(&buffer_snap);
 8459                let end = symbol.range.end.to_offset(&buffer_snap);
 8460                let new_range = start..end;
 8461                if start < selection.start || end > selection.end {
 8462                    return Some(Selection {
 8463                        id: selection.id,
 8464                        start: new_range.start,
 8465                        end: new_range.end,
 8466                        goal: SelectionGoal::None,
 8467                        reversed: selection.reversed,
 8468                    });
 8469                }
 8470            }
 8471            None
 8472        }
 8473
 8474        let mut selected_larger_symbol = false;
 8475        let new_selections = old_selections
 8476            .iter()
 8477            .map(|selection| match update_selection(selection, &buffer) {
 8478                Some(new_selection) => {
 8479                    if new_selection.range() != selection.range() {
 8480                        selected_larger_symbol = true;
 8481                    }
 8482                    new_selection
 8483                }
 8484                None => selection.clone(),
 8485            })
 8486            .collect::<Vec<_>>();
 8487
 8488        if selected_larger_symbol {
 8489            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8490                s.select(new_selections);
 8491            });
 8492        }
 8493    }
 8494
 8495    pub fn select_larger_syntax_node(
 8496        &mut self,
 8497        _: &SelectLargerSyntaxNode,
 8498        cx: &mut ViewContext<Self>,
 8499    ) {
 8500        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8501        let buffer = self.buffer.read(cx).snapshot(cx);
 8502        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 8503
 8504        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 8505        let mut selected_larger_node = false;
 8506        let new_selections = old_selections
 8507            .iter()
 8508            .map(|selection| {
 8509                let old_range = selection.start..selection.end;
 8510                let mut new_range = old_range.clone();
 8511                while let Some(containing_range) =
 8512                    buffer.range_for_syntax_ancestor(new_range.clone())
 8513                {
 8514                    new_range = containing_range;
 8515                    if !display_map.intersects_fold(new_range.start)
 8516                        && !display_map.intersects_fold(new_range.end)
 8517                    {
 8518                        break;
 8519                    }
 8520                }
 8521
 8522                selected_larger_node |= new_range != old_range;
 8523                Selection {
 8524                    id: selection.id,
 8525                    start: new_range.start,
 8526                    end: new_range.end,
 8527                    goal: SelectionGoal::None,
 8528                    reversed: selection.reversed,
 8529                }
 8530            })
 8531            .collect::<Vec<_>>();
 8532
 8533        if selected_larger_node {
 8534            stack.push(old_selections);
 8535            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8536                s.select(new_selections);
 8537            });
 8538        }
 8539        self.select_larger_syntax_node_stack = stack;
 8540    }
 8541
 8542    pub fn select_smaller_syntax_node(
 8543        &mut self,
 8544        _: &SelectSmallerSyntaxNode,
 8545        cx: &mut ViewContext<Self>,
 8546    ) {
 8547        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 8548        if let Some(selections) = stack.pop() {
 8549            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8550                s.select(selections.to_vec());
 8551            });
 8552        }
 8553        self.select_larger_syntax_node_stack = stack;
 8554    }
 8555
 8556    fn refresh_runnables(&mut self, cx: &mut ViewContext<Self>) -> Task<()> {
 8557        if !EditorSettings::get_global(cx).gutter.runnables {
 8558            self.clear_tasks();
 8559            return Task::ready(());
 8560        }
 8561        let project = self.project.clone();
 8562        cx.spawn(|this, mut cx| async move {
 8563            let Ok(display_snapshot) = this.update(&mut cx, |this, cx| {
 8564                this.display_map.update(cx, |map, cx| map.snapshot(cx))
 8565            }) else {
 8566                return;
 8567            };
 8568
 8569            let Some(project) = project else {
 8570                return;
 8571            };
 8572
 8573            let hide_runnables = project
 8574                .update(&mut cx, |project, cx| {
 8575                    // Do not display any test indicators in non-dev server remote projects.
 8576                    project.is_remote() && project.ssh_connection_string(cx).is_none()
 8577                })
 8578                .unwrap_or(true);
 8579            if hide_runnables {
 8580                return;
 8581            }
 8582            let new_rows =
 8583                cx.background_executor()
 8584                    .spawn({
 8585                        let snapshot = display_snapshot.clone();
 8586                        async move {
 8587                            Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
 8588                        }
 8589                    })
 8590                    .await;
 8591            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
 8592
 8593            this.update(&mut cx, |this, _| {
 8594                this.clear_tasks();
 8595                for (key, value) in rows {
 8596                    this.insert_tasks(key, value);
 8597                }
 8598            })
 8599            .ok();
 8600        })
 8601    }
 8602    fn fetch_runnable_ranges(
 8603        snapshot: &DisplaySnapshot,
 8604        range: Range<Anchor>,
 8605    ) -> Vec<language::RunnableRange> {
 8606        snapshot.buffer_snapshot.runnable_ranges(range).collect()
 8607    }
 8608
 8609    fn runnable_rows(
 8610        project: Model<Project>,
 8611        snapshot: DisplaySnapshot,
 8612        runnable_ranges: Vec<RunnableRange>,
 8613        mut cx: AsyncWindowContext,
 8614    ) -> Vec<((BufferId, u32), RunnableTasks)> {
 8615        runnable_ranges
 8616            .into_iter()
 8617            .filter_map(|mut runnable| {
 8618                let tasks = cx
 8619                    .update(|cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
 8620                    .ok()?;
 8621                if tasks.is_empty() {
 8622                    return None;
 8623                }
 8624
 8625                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
 8626
 8627                let row = snapshot
 8628                    .buffer_snapshot
 8629                    .buffer_line_for_row(MultiBufferRow(point.row))?
 8630                    .1
 8631                    .start
 8632                    .row;
 8633
 8634                let context_range =
 8635                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
 8636                Some((
 8637                    (runnable.buffer_id, row),
 8638                    RunnableTasks {
 8639                        templates: tasks,
 8640                        offset: MultiBufferOffset(runnable.run_range.start),
 8641                        context_range,
 8642                        column: point.column,
 8643                        extra_variables: runnable.extra_captures,
 8644                    },
 8645                ))
 8646            })
 8647            .collect()
 8648    }
 8649
 8650    fn templates_with_tags(
 8651        project: &Model<Project>,
 8652        runnable: &mut Runnable,
 8653        cx: &WindowContext<'_>,
 8654    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
 8655        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
 8656            let (worktree_id, file) = project
 8657                .buffer_for_id(runnable.buffer, cx)
 8658                .and_then(|buffer| buffer.read(cx).file())
 8659                .map(|file| (WorktreeId::from_usize(file.worktree_id()), file.clone()))
 8660                .unzip();
 8661
 8662            (project.task_inventory().clone(), worktree_id, file)
 8663        });
 8664
 8665        let inventory = inventory.read(cx);
 8666        let tags = mem::take(&mut runnable.tags);
 8667        let mut tags: Vec<_> = tags
 8668            .into_iter()
 8669            .flat_map(|tag| {
 8670                let tag = tag.0.clone();
 8671                inventory
 8672                    .list_tasks(
 8673                        file.clone(),
 8674                        Some(runnable.language.clone()),
 8675                        worktree_id,
 8676                        cx,
 8677                    )
 8678                    .into_iter()
 8679                    .filter(move |(_, template)| {
 8680                        template.tags.iter().any(|source_tag| source_tag == &tag)
 8681                    })
 8682            })
 8683            .sorted_by_key(|(kind, _)| kind.to_owned())
 8684            .collect();
 8685        if let Some((leading_tag_source, _)) = tags.first() {
 8686            // Strongest source wins; if we have worktree tag binding, prefer that to
 8687            // global and language bindings;
 8688            // if we have a global binding, prefer that to language binding.
 8689            let first_mismatch = tags
 8690                .iter()
 8691                .position(|(tag_source, _)| tag_source != leading_tag_source);
 8692            if let Some(index) = first_mismatch {
 8693                tags.truncate(index);
 8694            }
 8695        }
 8696
 8697        tags
 8698    }
 8699
 8700    pub fn move_to_enclosing_bracket(
 8701        &mut self,
 8702        _: &MoveToEnclosingBracket,
 8703        cx: &mut ViewContext<Self>,
 8704    ) {
 8705        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8706            s.move_offsets_with(|snapshot, selection| {
 8707                let Some(enclosing_bracket_ranges) =
 8708                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
 8709                else {
 8710                    return;
 8711                };
 8712
 8713                let mut best_length = usize::MAX;
 8714                let mut best_inside = false;
 8715                let mut best_in_bracket_range = false;
 8716                let mut best_destination = None;
 8717                for (open, close) in enclosing_bracket_ranges {
 8718                    let close = close.to_inclusive();
 8719                    let length = close.end() - open.start;
 8720                    let inside = selection.start >= open.end && selection.end <= *close.start();
 8721                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
 8722                        || close.contains(&selection.head());
 8723
 8724                    // If best is next to a bracket and current isn't, skip
 8725                    if !in_bracket_range && best_in_bracket_range {
 8726                        continue;
 8727                    }
 8728
 8729                    // Prefer smaller lengths unless best is inside and current isn't
 8730                    if length > best_length && (best_inside || !inside) {
 8731                        continue;
 8732                    }
 8733
 8734                    best_length = length;
 8735                    best_inside = inside;
 8736                    best_in_bracket_range = in_bracket_range;
 8737                    best_destination = Some(
 8738                        if close.contains(&selection.start) && close.contains(&selection.end) {
 8739                            if inside {
 8740                                open.end
 8741                            } else {
 8742                                open.start
 8743                            }
 8744                        } else {
 8745                            if inside {
 8746                                *close.start()
 8747                            } else {
 8748                                *close.end()
 8749                            }
 8750                        },
 8751                    );
 8752                }
 8753
 8754                if let Some(destination) = best_destination {
 8755                    selection.collapse_to(destination, SelectionGoal::None);
 8756                }
 8757            })
 8758        });
 8759    }
 8760
 8761    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 8762        self.end_selection(cx);
 8763        self.selection_history.mode = SelectionHistoryMode::Undoing;
 8764        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 8765            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 8766            self.select_next_state = entry.select_next_state;
 8767            self.select_prev_state = entry.select_prev_state;
 8768            self.add_selections_state = entry.add_selections_state;
 8769            self.request_autoscroll(Autoscroll::newest(), cx);
 8770        }
 8771        self.selection_history.mode = SelectionHistoryMode::Normal;
 8772    }
 8773
 8774    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 8775        self.end_selection(cx);
 8776        self.selection_history.mode = SelectionHistoryMode::Redoing;
 8777        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 8778            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 8779            self.select_next_state = entry.select_next_state;
 8780            self.select_prev_state = entry.select_prev_state;
 8781            self.add_selections_state = entry.add_selections_state;
 8782            self.request_autoscroll(Autoscroll::newest(), cx);
 8783        }
 8784        self.selection_history.mode = SelectionHistoryMode::Normal;
 8785    }
 8786
 8787    pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext<Self>) {
 8788        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
 8789    }
 8790
 8791    pub fn expand_excerpts_down(
 8792        &mut self,
 8793        action: &ExpandExcerptsDown,
 8794        cx: &mut ViewContext<Self>,
 8795    ) {
 8796        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
 8797    }
 8798
 8799    pub fn expand_excerpts_up(&mut self, action: &ExpandExcerptsUp, cx: &mut ViewContext<Self>) {
 8800        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
 8801    }
 8802
 8803    pub fn expand_excerpts_for_direction(
 8804        &mut self,
 8805        lines: u32,
 8806        direction: ExpandExcerptDirection,
 8807        cx: &mut ViewContext<Self>,
 8808    ) {
 8809        let selections = self.selections.disjoint_anchors();
 8810
 8811        let lines = if lines == 0 {
 8812            EditorSettings::get_global(cx).expand_excerpt_lines
 8813        } else {
 8814            lines
 8815        };
 8816
 8817        self.buffer.update(cx, |buffer, cx| {
 8818            buffer.expand_excerpts(
 8819                selections
 8820                    .into_iter()
 8821                    .map(|selection| selection.head().excerpt_id)
 8822                    .dedup(),
 8823                lines,
 8824                direction,
 8825                cx,
 8826            )
 8827        })
 8828    }
 8829
 8830    pub fn expand_excerpt(
 8831        &mut self,
 8832        excerpt: ExcerptId,
 8833        direction: ExpandExcerptDirection,
 8834        cx: &mut ViewContext<Self>,
 8835    ) {
 8836        let lines = EditorSettings::get_global(cx).expand_excerpt_lines;
 8837        self.buffer.update(cx, |buffer, cx| {
 8838            buffer.expand_excerpts([excerpt], lines, direction, cx)
 8839        })
 8840    }
 8841
 8842    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
 8843        self.go_to_diagnostic_impl(Direction::Next, cx)
 8844    }
 8845
 8846    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 8847        self.go_to_diagnostic_impl(Direction::Prev, cx)
 8848    }
 8849
 8850    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 8851        let buffer = self.buffer.read(cx).snapshot(cx);
 8852        let selection = self.selections.newest::<usize>(cx);
 8853
 8854        // If there is an active Diagnostic Popover jump to its diagnostic instead.
 8855        if direction == Direction::Next {
 8856            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
 8857                let (group_id, jump_to) = popover.activation_info();
 8858                if self.activate_diagnostics(group_id, cx) {
 8859                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8860                        let mut new_selection = s.newest_anchor().clone();
 8861                        new_selection.collapse_to(jump_to, SelectionGoal::None);
 8862                        s.select_anchors(vec![new_selection.clone()]);
 8863                    });
 8864                }
 8865                return;
 8866            }
 8867        }
 8868
 8869        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 8870            active_diagnostics
 8871                .primary_range
 8872                .to_offset(&buffer)
 8873                .to_inclusive()
 8874        });
 8875        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 8876            if active_primary_range.contains(&selection.head()) {
 8877                *active_primary_range.start()
 8878            } else {
 8879                selection.head()
 8880            }
 8881        } else {
 8882            selection.head()
 8883        };
 8884        let snapshot = self.snapshot(cx);
 8885        loop {
 8886            let diagnostics = if direction == Direction::Prev {
 8887                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 8888            } else {
 8889                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 8890            }
 8891            .filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
 8892            let group = diagnostics
 8893                // relies on diagnostics_in_range to return diagnostics with the same starting range to
 8894                // be sorted in a stable way
 8895                // skip until we are at current active diagnostic, if it exists
 8896                .skip_while(|entry| {
 8897                    (match direction {
 8898                        Direction::Prev => entry.range.start >= search_start,
 8899                        Direction::Next => entry.range.start <= search_start,
 8900                    }) && self
 8901                        .active_diagnostics
 8902                        .as_ref()
 8903                        .is_some_and(|a| a.group_id != entry.diagnostic.group_id)
 8904                })
 8905                .find_map(|entry| {
 8906                    if entry.diagnostic.is_primary
 8907                        && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 8908                        && !entry.range.is_empty()
 8909                        // if we match with the active diagnostic, skip it
 8910                        && Some(entry.diagnostic.group_id)
 8911                            != self.active_diagnostics.as_ref().map(|d| d.group_id)
 8912                    {
 8913                        Some((entry.range, entry.diagnostic.group_id))
 8914                    } else {
 8915                        None
 8916                    }
 8917                });
 8918
 8919            if let Some((primary_range, group_id)) = group {
 8920                if self.activate_diagnostics(group_id, cx) {
 8921                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 8922                        s.select(vec![Selection {
 8923                            id: selection.id,
 8924                            start: primary_range.start,
 8925                            end: primary_range.start,
 8926                            reversed: false,
 8927                            goal: SelectionGoal::None,
 8928                        }]);
 8929                    });
 8930                }
 8931                break;
 8932            } else {
 8933                // Cycle around to the start of the buffer, potentially moving back to the start of
 8934                // the currently active diagnostic.
 8935                active_primary_range.take();
 8936                if direction == Direction::Prev {
 8937                    if search_start == buffer.len() {
 8938                        break;
 8939                    } else {
 8940                        search_start = buffer.len();
 8941                    }
 8942                } else if search_start == 0 {
 8943                    break;
 8944                } else {
 8945                    search_start = 0;
 8946                }
 8947            }
 8948        }
 8949    }
 8950
 8951    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
 8952        let snapshot = self
 8953            .display_map
 8954            .update(cx, |display_map, cx| display_map.snapshot(cx));
 8955        let selection = self.selections.newest::<Point>(cx);
 8956
 8957        if !self.seek_in_direction(
 8958            &snapshot,
 8959            selection.head(),
 8960            false,
 8961            snapshot.buffer_snapshot.git_diff_hunks_in_range(
 8962                MultiBufferRow(selection.head().row + 1)..MultiBufferRow::MAX,
 8963            ),
 8964            cx,
 8965        ) {
 8966            let wrapped_point = Point::zero();
 8967            self.seek_in_direction(
 8968                &snapshot,
 8969                wrapped_point,
 8970                true,
 8971                snapshot.buffer_snapshot.git_diff_hunks_in_range(
 8972                    MultiBufferRow(wrapped_point.row + 1)..MultiBufferRow::MAX,
 8973                ),
 8974                cx,
 8975            );
 8976        }
 8977    }
 8978
 8979    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
 8980        let snapshot = self
 8981            .display_map
 8982            .update(cx, |display_map, cx| display_map.snapshot(cx));
 8983        let selection = self.selections.newest::<Point>(cx);
 8984
 8985        if !self.seek_in_direction(
 8986            &snapshot,
 8987            selection.head(),
 8988            false,
 8989            snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
 8990                MultiBufferRow(0)..MultiBufferRow(selection.head().row),
 8991            ),
 8992            cx,
 8993        ) {
 8994            let wrapped_point = snapshot.buffer_snapshot.max_point();
 8995            self.seek_in_direction(
 8996                &snapshot,
 8997                wrapped_point,
 8998                true,
 8999                snapshot.buffer_snapshot.git_diff_hunks_in_range_rev(
 9000                    MultiBufferRow(0)..MultiBufferRow(wrapped_point.row),
 9001                ),
 9002                cx,
 9003            );
 9004        }
 9005    }
 9006
 9007    fn seek_in_direction(
 9008        &mut self,
 9009        snapshot: &DisplaySnapshot,
 9010        initial_point: Point,
 9011        is_wrapped: bool,
 9012        hunks: impl Iterator<Item = DiffHunk<MultiBufferRow>>,
 9013        cx: &mut ViewContext<Editor>,
 9014    ) -> bool {
 9015        let display_point = initial_point.to_display_point(snapshot);
 9016        let mut hunks = hunks
 9017            .map(|hunk| diff_hunk_to_display(&hunk, &snapshot))
 9018            .filter(|hunk| is_wrapped || !hunk.contains_display_row(display_point.row()))
 9019            .dedup();
 9020
 9021        if let Some(hunk) = hunks.next() {
 9022            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9023                let row = hunk.start_display_row();
 9024                let point = DisplayPoint::new(row, 0);
 9025                s.select_display_ranges([point..point]);
 9026            });
 9027
 9028            true
 9029        } else {
 9030            false
 9031        }
 9032    }
 9033
 9034    pub fn go_to_definition(
 9035        &mut self,
 9036        _: &GoToDefinition,
 9037        cx: &mut ViewContext<Self>,
 9038    ) -> Task<Result<Navigated>> {
 9039        let definition = self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
 9040        let references = self.find_all_references(&FindAllReferences, cx);
 9041        cx.background_executor().spawn(async move {
 9042            if definition.await? == Navigated::Yes {
 9043                return Ok(Navigated::Yes);
 9044            }
 9045            if let Some(references) = references {
 9046                if references.await? == Navigated::Yes {
 9047                    return Ok(Navigated::Yes);
 9048                }
 9049            }
 9050
 9051            Ok(Navigated::No)
 9052        })
 9053    }
 9054
 9055    pub fn go_to_declaration(
 9056        &mut self,
 9057        _: &GoToDeclaration,
 9058        cx: &mut ViewContext<Self>,
 9059    ) -> Task<Result<Navigated>> {
 9060        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, cx)
 9061    }
 9062
 9063    pub fn go_to_declaration_split(
 9064        &mut self,
 9065        _: &GoToDeclaration,
 9066        cx: &mut ViewContext<Self>,
 9067    ) -> Task<Result<Navigated>> {
 9068        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, cx)
 9069    }
 9070
 9071    pub fn go_to_implementation(
 9072        &mut self,
 9073        _: &GoToImplementation,
 9074        cx: &mut ViewContext<Self>,
 9075    ) -> Task<Result<Navigated>> {
 9076        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx)
 9077    }
 9078
 9079    pub fn go_to_implementation_split(
 9080        &mut self,
 9081        _: &GoToImplementationSplit,
 9082        cx: &mut ViewContext<Self>,
 9083    ) -> Task<Result<Navigated>> {
 9084        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx)
 9085    }
 9086
 9087    pub fn go_to_type_definition(
 9088        &mut self,
 9089        _: &GoToTypeDefinition,
 9090        cx: &mut ViewContext<Self>,
 9091    ) -> Task<Result<Navigated>> {
 9092        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx)
 9093    }
 9094
 9095    pub fn go_to_definition_split(
 9096        &mut self,
 9097        _: &GoToDefinitionSplit,
 9098        cx: &mut ViewContext<Self>,
 9099    ) -> Task<Result<Navigated>> {
 9100        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx)
 9101    }
 9102
 9103    pub fn go_to_type_definition_split(
 9104        &mut self,
 9105        _: &GoToTypeDefinitionSplit,
 9106        cx: &mut ViewContext<Self>,
 9107    ) -> Task<Result<Navigated>> {
 9108        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx)
 9109    }
 9110
 9111    fn go_to_definition_of_kind(
 9112        &mut self,
 9113        kind: GotoDefinitionKind,
 9114        split: bool,
 9115        cx: &mut ViewContext<Self>,
 9116    ) -> Task<Result<Navigated>> {
 9117        let Some(workspace) = self.workspace() else {
 9118            return Task::ready(Ok(Navigated::No));
 9119        };
 9120        let buffer = self.buffer.read(cx);
 9121        let head = self.selections.newest::<usize>(cx).head();
 9122        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 9123            text_anchor
 9124        } else {
 9125            return Task::ready(Ok(Navigated::No));
 9126        };
 9127
 9128        let project = workspace.read(cx).project().clone();
 9129        let definitions = project.update(cx, |project, cx| match kind {
 9130            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
 9131            GotoDefinitionKind::Declaration => project.declaration(&buffer, head, cx),
 9132            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
 9133            GotoDefinitionKind::Implementation => project.implementation(&buffer, head, cx),
 9134        });
 9135
 9136        cx.spawn(|editor, mut cx| async move {
 9137            let definitions = definitions.await?;
 9138            let navigated = editor
 9139                .update(&mut cx, |editor, cx| {
 9140                    editor.navigate_to_hover_links(
 9141                        Some(kind),
 9142                        definitions
 9143                            .into_iter()
 9144                            .filter(|location| {
 9145                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
 9146                            })
 9147                            .map(HoverLink::Text)
 9148                            .collect::<Vec<_>>(),
 9149                        split,
 9150                        cx,
 9151                    )
 9152                })?
 9153                .await?;
 9154            anyhow::Ok(navigated)
 9155        })
 9156    }
 9157
 9158    pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext<Self>) {
 9159        let position = self.selections.newest_anchor().head();
 9160        let Some((buffer, buffer_position)) =
 9161            self.buffer.read(cx).text_anchor_for_position(position, cx)
 9162        else {
 9163            return;
 9164        };
 9165
 9166        cx.spawn(|editor, mut cx| async move {
 9167            if let Some((_, url)) = find_url(&buffer, buffer_position, cx.clone()) {
 9168                editor.update(&mut cx, |_, cx| {
 9169                    cx.open_url(&url);
 9170                })
 9171            } else {
 9172                Ok(())
 9173            }
 9174        })
 9175        .detach();
 9176    }
 9177
 9178    pub(crate) fn navigate_to_hover_links(
 9179        &mut self,
 9180        kind: Option<GotoDefinitionKind>,
 9181        mut definitions: Vec<HoverLink>,
 9182        split: bool,
 9183        cx: &mut ViewContext<Editor>,
 9184    ) -> Task<Result<Navigated>> {
 9185        // If there is one definition, just open it directly
 9186        if definitions.len() == 1 {
 9187            let definition = definitions.pop().unwrap();
 9188            let target_task = match definition {
 9189                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 9190                HoverLink::InlayHint(lsp_location, server_id) => {
 9191                    self.compute_target_location(lsp_location, server_id, cx)
 9192                }
 9193                HoverLink::Url(url) => {
 9194                    cx.open_url(&url);
 9195                    Task::ready(Ok(None))
 9196                }
 9197            };
 9198            cx.spawn(|editor, mut cx| async move {
 9199                let target = target_task.await.context("target resolution task")?;
 9200                let Some(target) = target else {
 9201                    return Ok(Navigated::No);
 9202                };
 9203                editor.update(&mut cx, |editor, cx| {
 9204                    let Some(workspace) = editor.workspace() else {
 9205                        return Navigated::No;
 9206                    };
 9207                    let pane = workspace.read(cx).active_pane().clone();
 9208
 9209                    let range = target.range.to_offset(target.buffer.read(cx));
 9210                    let range = editor.range_for_match(&range);
 9211
 9212                    if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
 9213                        let buffer = target.buffer.read(cx);
 9214                        let range = check_multiline_range(buffer, range);
 9215                        editor.change_selections(Some(Autoscroll::focused()), cx, |s| {
 9216                            s.select_ranges([range]);
 9217                        });
 9218                    } else {
 9219                        cx.window_context().defer(move |cx| {
 9220                            let target_editor: View<Self> =
 9221                                workspace.update(cx, |workspace, cx| {
 9222                                    let pane = if split {
 9223                                        workspace.adjacent_pane(cx)
 9224                                    } else {
 9225                                        workspace.active_pane().clone()
 9226                                    };
 9227
 9228                                    workspace.open_project_item(
 9229                                        pane,
 9230                                        target.buffer.clone(),
 9231                                        true,
 9232                                        true,
 9233                                        cx,
 9234                                    )
 9235                                });
 9236                            target_editor.update(cx, |target_editor, cx| {
 9237                                // When selecting a definition in a different buffer, disable the nav history
 9238                                // to avoid creating a history entry at the previous cursor location.
 9239                                pane.update(cx, |pane, _| pane.disable_history());
 9240                                let buffer = target.buffer.read(cx);
 9241                                let range = check_multiline_range(buffer, range);
 9242                                target_editor.change_selections(
 9243                                    Some(Autoscroll::focused()),
 9244                                    cx,
 9245                                    |s| {
 9246                                        s.select_ranges([range]);
 9247                                    },
 9248                                );
 9249                                pane.update(cx, |pane, _| pane.enable_history());
 9250                            });
 9251                        });
 9252                    }
 9253                    Navigated::Yes
 9254                })
 9255            })
 9256        } else if !definitions.is_empty() {
 9257            let replica_id = self.replica_id(cx);
 9258            cx.spawn(|editor, mut cx| async move {
 9259                let (title, location_tasks, workspace) = editor
 9260                    .update(&mut cx, |editor, cx| {
 9261                        let tab_kind = match kind {
 9262                            Some(GotoDefinitionKind::Implementation) => "Implementations",
 9263                            _ => "Definitions",
 9264                        };
 9265                        let title = definitions
 9266                            .iter()
 9267                            .find_map(|definition| match definition {
 9268                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
 9269                                    let buffer = origin.buffer.read(cx);
 9270                                    format!(
 9271                                        "{} for {}",
 9272                                        tab_kind,
 9273                                        buffer
 9274                                            .text_for_range(origin.range.clone())
 9275                                            .collect::<String>()
 9276                                    )
 9277                                }),
 9278                                HoverLink::InlayHint(_, _) => None,
 9279                                HoverLink::Url(_) => None,
 9280                            })
 9281                            .unwrap_or(tab_kind.to_string());
 9282                        let location_tasks = definitions
 9283                            .into_iter()
 9284                            .map(|definition| match definition {
 9285                                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 9286                                HoverLink::InlayHint(lsp_location, server_id) => {
 9287                                    editor.compute_target_location(lsp_location, server_id, cx)
 9288                                }
 9289                                HoverLink::Url(_) => Task::ready(Ok(None)),
 9290                            })
 9291                            .collect::<Vec<_>>();
 9292                        (title, location_tasks, editor.workspace().clone())
 9293                    })
 9294                    .context("location tasks preparation")?;
 9295
 9296                let locations = futures::future::join_all(location_tasks)
 9297                    .await
 9298                    .into_iter()
 9299                    .filter_map(|location| location.transpose())
 9300                    .collect::<Result<_>>()
 9301                    .context("location tasks")?;
 9302
 9303                let Some(workspace) = workspace else {
 9304                    return Ok(Navigated::No);
 9305                };
 9306                let opened = workspace
 9307                    .update(&mut cx, |workspace, cx| {
 9308                        Self::open_locations_in_multibuffer(
 9309                            workspace, locations, replica_id, title, split, cx,
 9310                        )
 9311                    })
 9312                    .ok();
 9313
 9314                anyhow::Ok(Navigated::from_bool(opened.is_some()))
 9315            })
 9316        } else {
 9317            Task::ready(Ok(Navigated::No))
 9318        }
 9319    }
 9320
 9321    fn compute_target_location(
 9322        &self,
 9323        lsp_location: lsp::Location,
 9324        server_id: LanguageServerId,
 9325        cx: &mut ViewContext<Editor>,
 9326    ) -> Task<anyhow::Result<Option<Location>>> {
 9327        let Some(project) = self.project.clone() else {
 9328            return Task::Ready(Some(Ok(None)));
 9329        };
 9330
 9331        cx.spawn(move |editor, mut cx| async move {
 9332            let location_task = editor.update(&mut cx, |editor, cx| {
 9333                project.update(cx, |project, cx| {
 9334                    let language_server_name =
 9335                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
 9336                            project
 9337                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 9338                                .map(|(lsp_adapter, _)| lsp_adapter.name.clone())
 9339                        });
 9340                    language_server_name.map(|language_server_name| {
 9341                        project.open_local_buffer_via_lsp(
 9342                            lsp_location.uri.clone(),
 9343                            server_id,
 9344                            language_server_name,
 9345                            cx,
 9346                        )
 9347                    })
 9348                })
 9349            })?;
 9350            let location = match location_task {
 9351                Some(task) => Some({
 9352                    let target_buffer_handle = task.await.context("open local buffer")?;
 9353                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
 9354                        let target_start = target_buffer
 9355                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 9356                        let target_end = target_buffer
 9357                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 9358                        target_buffer.anchor_after(target_start)
 9359                            ..target_buffer.anchor_before(target_end)
 9360                    })?;
 9361                    Location {
 9362                        buffer: target_buffer_handle,
 9363                        range,
 9364                    }
 9365                }),
 9366                None => None,
 9367            };
 9368            Ok(location)
 9369        })
 9370    }
 9371
 9372    pub fn find_all_references(
 9373        &mut self,
 9374        _: &FindAllReferences,
 9375        cx: &mut ViewContext<Self>,
 9376    ) -> Option<Task<Result<Navigated>>> {
 9377        let multi_buffer = self.buffer.read(cx);
 9378        let selection = self.selections.newest::<usize>(cx);
 9379        let head = selection.head();
 9380
 9381        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 9382        let head_anchor = multi_buffer_snapshot.anchor_at(
 9383            head,
 9384            if head < selection.tail() {
 9385                Bias::Right
 9386            } else {
 9387                Bias::Left
 9388            },
 9389        );
 9390
 9391        match self
 9392            .find_all_references_task_sources
 9393            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
 9394        {
 9395            Ok(_) => {
 9396                log::info!(
 9397                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
 9398                );
 9399                return None;
 9400            }
 9401            Err(i) => {
 9402                self.find_all_references_task_sources.insert(i, head_anchor);
 9403            }
 9404        }
 9405
 9406        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
 9407        let replica_id = self.replica_id(cx);
 9408        let workspace = self.workspace()?;
 9409        let project = workspace.read(cx).project().clone();
 9410        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
 9411        Some(cx.spawn(|editor, mut cx| async move {
 9412            let _cleanup = defer({
 9413                let mut cx = cx.clone();
 9414                move || {
 9415                    let _ = editor.update(&mut cx, |editor, _| {
 9416                        if let Ok(i) =
 9417                            editor
 9418                                .find_all_references_task_sources
 9419                                .binary_search_by(|anchor| {
 9420                                    anchor.cmp(&head_anchor, &multi_buffer_snapshot)
 9421                                })
 9422                        {
 9423                            editor.find_all_references_task_sources.remove(i);
 9424                        }
 9425                    });
 9426                }
 9427            });
 9428
 9429            let locations = references.await?;
 9430            if locations.is_empty() {
 9431                return anyhow::Ok(Navigated::No);
 9432            }
 9433
 9434            workspace.update(&mut cx, |workspace, cx| {
 9435                let title = locations
 9436                    .first()
 9437                    .as_ref()
 9438                    .map(|location| {
 9439                        let buffer = location.buffer.read(cx);
 9440                        format!(
 9441                            "References to `{}`",
 9442                            buffer
 9443                                .text_for_range(location.range.clone())
 9444                                .collect::<String>()
 9445                        )
 9446                    })
 9447                    .unwrap();
 9448                Self::open_locations_in_multibuffer(
 9449                    workspace, locations, replica_id, title, false, cx,
 9450                );
 9451                Navigated::Yes
 9452            })
 9453        }))
 9454    }
 9455
 9456    /// Opens a multibuffer with the given project locations in it
 9457    pub fn open_locations_in_multibuffer(
 9458        workspace: &mut Workspace,
 9459        mut locations: Vec<Location>,
 9460        replica_id: ReplicaId,
 9461        title: String,
 9462        split: bool,
 9463        cx: &mut ViewContext<Workspace>,
 9464    ) {
 9465        // If there are multiple definitions, open them in a multibuffer
 9466        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
 9467        let mut locations = locations.into_iter().peekable();
 9468        let mut ranges_to_highlight = Vec::new();
 9469        let capability = workspace.project().read(cx).capability();
 9470
 9471        let excerpt_buffer = cx.new_model(|cx| {
 9472            let mut multibuffer = MultiBuffer::new(replica_id, capability);
 9473            while let Some(location) = locations.next() {
 9474                let buffer = location.buffer.read(cx);
 9475                let mut ranges_for_buffer = Vec::new();
 9476                let range = location.range.to_offset(buffer);
 9477                ranges_for_buffer.push(range.clone());
 9478
 9479                while let Some(next_location) = locations.peek() {
 9480                    if next_location.buffer == location.buffer {
 9481                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
 9482                        locations.next();
 9483                    } else {
 9484                        break;
 9485                    }
 9486                }
 9487
 9488                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
 9489                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
 9490                    location.buffer.clone(),
 9491                    ranges_for_buffer,
 9492                    DEFAULT_MULTIBUFFER_CONTEXT,
 9493                    cx,
 9494                ))
 9495            }
 9496
 9497            multibuffer.with_title(title)
 9498        });
 9499
 9500        let editor = cx.new_view(|cx| {
 9501            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), true, cx)
 9502        });
 9503        editor.update(cx, |editor, cx| {
 9504            if let Some(first_range) = ranges_to_highlight.first() {
 9505                editor.change_selections(None, cx, |selections| {
 9506                    selections.clear_disjoint();
 9507                    selections.select_anchor_ranges(std::iter::once(first_range.clone()));
 9508                });
 9509            }
 9510            editor.highlight_background::<Self>(
 9511                &ranges_to_highlight,
 9512                |theme| theme.editor_highlighted_line_background,
 9513                cx,
 9514            );
 9515        });
 9516
 9517        let item = Box::new(editor);
 9518        let item_id = item.item_id();
 9519
 9520        if split {
 9521            workspace.split_item(SplitDirection::Right, item.clone(), cx);
 9522        } else {
 9523            let destination_index = workspace.active_pane().update(cx, |pane, cx| {
 9524                if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
 9525                    pane.close_current_preview_item(cx)
 9526                } else {
 9527                    None
 9528                }
 9529            });
 9530            workspace.add_item_to_active_pane(item.clone(), destination_index, true, cx);
 9531        }
 9532        workspace.active_pane().update(cx, |pane, cx| {
 9533            pane.set_preview_item_id(Some(item_id), cx);
 9534        });
 9535    }
 9536
 9537    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 9538        use language::ToOffset as _;
 9539
 9540        let project = self.project.clone()?;
 9541        let selection = self.selections.newest_anchor().clone();
 9542        let (cursor_buffer, cursor_buffer_position) = self
 9543            .buffer
 9544            .read(cx)
 9545            .text_anchor_for_position(selection.head(), cx)?;
 9546        let (tail_buffer, cursor_buffer_position_end) = self
 9547            .buffer
 9548            .read(cx)
 9549            .text_anchor_for_position(selection.tail(), cx)?;
 9550        if tail_buffer != cursor_buffer {
 9551            return None;
 9552        }
 9553
 9554        let snapshot = cursor_buffer.read(cx).snapshot();
 9555        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
 9556        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
 9557        let prepare_rename = project.update(cx, |project, cx| {
 9558            project.prepare_rename(cursor_buffer.clone(), cursor_buffer_offset, cx)
 9559        });
 9560        drop(snapshot);
 9561
 9562        Some(cx.spawn(|this, mut cx| async move {
 9563            let rename_range = if let Some(range) = prepare_rename.await? {
 9564                Some(range)
 9565            } else {
 9566                this.update(&mut cx, |this, cx| {
 9567                    let buffer = this.buffer.read(cx).snapshot(cx);
 9568                    let mut buffer_highlights = this
 9569                        .document_highlights_for_position(selection.head(), &buffer)
 9570                        .filter(|highlight| {
 9571                            highlight.start.excerpt_id == selection.head().excerpt_id
 9572                                && highlight.end.excerpt_id == selection.head().excerpt_id
 9573                        });
 9574                    buffer_highlights
 9575                        .next()
 9576                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
 9577                })?
 9578            };
 9579            if let Some(rename_range) = rename_range {
 9580                this.update(&mut cx, |this, cx| {
 9581                    let snapshot = cursor_buffer.read(cx).snapshot();
 9582                    let rename_buffer_range = rename_range.to_offset(&snapshot);
 9583                    let cursor_offset_in_rename_range =
 9584                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
 9585                    let cursor_offset_in_rename_range_end =
 9586                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
 9587
 9588                    this.take_rename(false, cx);
 9589                    let buffer = this.buffer.read(cx).read(cx);
 9590                    let cursor_offset = selection.head().to_offset(&buffer);
 9591                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
 9592                    let rename_end = rename_start + rename_buffer_range.len();
 9593                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
 9594                    let mut old_highlight_id = None;
 9595                    let old_name: Arc<str> = buffer
 9596                        .chunks(rename_start..rename_end, true)
 9597                        .map(|chunk| {
 9598                            if old_highlight_id.is_none() {
 9599                                old_highlight_id = chunk.syntax_highlight_id;
 9600                            }
 9601                            chunk.text
 9602                        })
 9603                        .collect::<String>()
 9604                        .into();
 9605
 9606                    drop(buffer);
 9607
 9608                    // Position the selection in the rename editor so that it matches the current selection.
 9609                    this.show_local_selections = false;
 9610                    let rename_editor = cx.new_view(|cx| {
 9611                        let mut editor = Editor::single_line(cx);
 9612                        editor.buffer.update(cx, |buffer, cx| {
 9613                            buffer.edit([(0..0, old_name.clone())], None, cx)
 9614                        });
 9615                        let rename_selection_range = match cursor_offset_in_rename_range
 9616                            .cmp(&cursor_offset_in_rename_range_end)
 9617                        {
 9618                            Ordering::Equal => {
 9619                                editor.select_all(&SelectAll, cx);
 9620                                return editor;
 9621                            }
 9622                            Ordering::Less => {
 9623                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
 9624                            }
 9625                            Ordering::Greater => {
 9626                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
 9627                            }
 9628                        };
 9629                        if rename_selection_range.end > old_name.len() {
 9630                            editor.select_all(&SelectAll, cx);
 9631                        } else {
 9632                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 9633                                s.select_ranges([rename_selection_range]);
 9634                            });
 9635                        }
 9636                        editor
 9637                    });
 9638                    cx.subscribe(&rename_editor, |_, _, e, cx| match e {
 9639                        EditorEvent::Focused => cx.emit(EditorEvent::FocusedIn),
 9640                        _ => {}
 9641                    })
 9642                    .detach();
 9643
 9644                    let write_highlights =
 9645                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
 9646                    let read_highlights =
 9647                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
 9648                    let ranges = write_highlights
 9649                        .iter()
 9650                        .flat_map(|(_, ranges)| ranges.iter())
 9651                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
 9652                        .cloned()
 9653                        .collect();
 9654
 9655                    this.highlight_text::<Rename>(
 9656                        ranges,
 9657                        HighlightStyle {
 9658                            fade_out: Some(0.6),
 9659                            ..Default::default()
 9660                        },
 9661                        cx,
 9662                    );
 9663                    let rename_focus_handle = rename_editor.focus_handle(cx);
 9664                    cx.focus(&rename_focus_handle);
 9665                    let block_id = this.insert_blocks(
 9666                        [BlockProperties {
 9667                            style: BlockStyle::Flex,
 9668                            position: range.start,
 9669                            height: 1,
 9670                            render: Box::new({
 9671                                let rename_editor = rename_editor.clone();
 9672                                move |cx: &mut BlockContext| {
 9673                                    let mut text_style = cx.editor_style.text.clone();
 9674                                    if let Some(highlight_style) = old_highlight_id
 9675                                        .and_then(|h| h.style(&cx.editor_style.syntax))
 9676                                    {
 9677                                        text_style = text_style.highlight(highlight_style);
 9678                                    }
 9679                                    div()
 9680                                        .pl(cx.anchor_x)
 9681                                        .child(EditorElement::new(
 9682                                            &rename_editor,
 9683                                            EditorStyle {
 9684                                                background: cx.theme().system().transparent,
 9685                                                local_player: cx.editor_style.local_player,
 9686                                                text: text_style,
 9687                                                scrollbar_width: cx.editor_style.scrollbar_width,
 9688                                                syntax: cx.editor_style.syntax.clone(),
 9689                                                status: cx.editor_style.status.clone(),
 9690                                                inlay_hints_style: HighlightStyle {
 9691                                                    color: Some(cx.theme().status().hint),
 9692                                                    font_weight: Some(FontWeight::BOLD),
 9693                                                    ..HighlightStyle::default()
 9694                                                },
 9695                                                suggestions_style: HighlightStyle {
 9696                                                    color: Some(cx.theme().status().predictive),
 9697                                                    ..HighlightStyle::default()
 9698                                                },
 9699                                                ..EditorStyle::default()
 9700                                            },
 9701                                        ))
 9702                                        .into_any_element()
 9703                                }
 9704                            }),
 9705                            disposition: BlockDisposition::Below,
 9706                            priority: 0,
 9707                        }],
 9708                        Some(Autoscroll::fit()),
 9709                        cx,
 9710                    )[0];
 9711                    this.pending_rename = Some(RenameState {
 9712                        range,
 9713                        old_name,
 9714                        editor: rename_editor,
 9715                        block_id,
 9716                    });
 9717                })?;
 9718            }
 9719
 9720            Ok(())
 9721        }))
 9722    }
 9723
 9724    pub fn confirm_rename(
 9725        &mut self,
 9726        _: &ConfirmRename,
 9727        cx: &mut ViewContext<Self>,
 9728    ) -> Option<Task<Result<()>>> {
 9729        let rename = self.take_rename(false, cx)?;
 9730        let workspace = self.workspace()?;
 9731        let (start_buffer, start) = self
 9732            .buffer
 9733            .read(cx)
 9734            .text_anchor_for_position(rename.range.start, cx)?;
 9735        let (end_buffer, end) = self
 9736            .buffer
 9737            .read(cx)
 9738            .text_anchor_for_position(rename.range.end, cx)?;
 9739        if start_buffer != end_buffer {
 9740            return None;
 9741        }
 9742
 9743        let buffer = start_buffer;
 9744        let range = start..end;
 9745        let old_name = rename.old_name;
 9746        let new_name = rename.editor.read(cx).text(cx);
 9747
 9748        let rename = workspace
 9749            .read(cx)
 9750            .project()
 9751            .clone()
 9752            .update(cx, |project, cx| {
 9753                project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
 9754            });
 9755        let workspace = workspace.downgrade();
 9756
 9757        Some(cx.spawn(|editor, mut cx| async move {
 9758            let project_transaction = rename.await?;
 9759            Self::open_project_transaction(
 9760                &editor,
 9761                workspace,
 9762                project_transaction,
 9763                format!("Rename: {}{}", old_name, new_name),
 9764                cx.clone(),
 9765            )
 9766            .await?;
 9767
 9768            editor.update(&mut cx, |editor, cx| {
 9769                editor.refresh_document_highlights(cx);
 9770            })?;
 9771            Ok(())
 9772        }))
 9773    }
 9774
 9775    fn take_rename(
 9776        &mut self,
 9777        moving_cursor: bool,
 9778        cx: &mut ViewContext<Self>,
 9779    ) -> Option<RenameState> {
 9780        let rename = self.pending_rename.take()?;
 9781        if rename.editor.focus_handle(cx).is_focused(cx) {
 9782            cx.focus(&self.focus_handle);
 9783        }
 9784
 9785        self.remove_blocks(
 9786            [rename.block_id].into_iter().collect(),
 9787            Some(Autoscroll::fit()),
 9788            cx,
 9789        );
 9790        self.clear_highlights::<Rename>(cx);
 9791        self.show_local_selections = true;
 9792
 9793        if moving_cursor {
 9794            let rename_editor = rename.editor.read(cx);
 9795            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
 9796
 9797            // Update the selection to match the position of the selection inside
 9798            // the rename editor.
 9799            let snapshot = self.buffer.read(cx).read(cx);
 9800            let rename_range = rename.range.to_offset(&snapshot);
 9801            let cursor_in_editor = snapshot
 9802                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
 9803                .min(rename_range.end);
 9804            drop(snapshot);
 9805
 9806            self.change_selections(None, cx, |s| {
 9807                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
 9808            });
 9809        } else {
 9810            self.refresh_document_highlights(cx);
 9811        }
 9812
 9813        Some(rename)
 9814    }
 9815
 9816    pub fn pending_rename(&self) -> Option<&RenameState> {
 9817        self.pending_rename.as_ref()
 9818    }
 9819
 9820    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 9821        let project = match &self.project {
 9822            Some(project) => project.clone(),
 9823            None => return None,
 9824        };
 9825
 9826        Some(self.perform_format(project, FormatTrigger::Manual, cx))
 9827    }
 9828
 9829    fn perform_format(
 9830        &mut self,
 9831        project: Model<Project>,
 9832        trigger: FormatTrigger,
 9833        cx: &mut ViewContext<Self>,
 9834    ) -> Task<Result<()>> {
 9835        let buffer = self.buffer().clone();
 9836        let mut buffers = buffer.read(cx).all_buffers();
 9837        if trigger == FormatTrigger::Save {
 9838            buffers.retain(|buffer| buffer.read(cx).is_dirty());
 9839        }
 9840
 9841        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
 9842        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
 9843
 9844        cx.spawn(|_, mut cx| async move {
 9845            let transaction = futures::select_biased! {
 9846                () = timeout => {
 9847                    log::warn!("timed out waiting for formatting");
 9848                    None
 9849                }
 9850                transaction = format.log_err().fuse() => transaction,
 9851            };
 9852
 9853            buffer
 9854                .update(&mut cx, |buffer, cx| {
 9855                    if let Some(transaction) = transaction {
 9856                        if !buffer.is_singleton() {
 9857                            buffer.push_transaction(&transaction.0, cx);
 9858                        }
 9859                    }
 9860
 9861                    cx.notify();
 9862                })
 9863                .ok();
 9864
 9865            Ok(())
 9866        })
 9867    }
 9868
 9869    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
 9870        if let Some(project) = self.project.clone() {
 9871            self.buffer.update(cx, |multi_buffer, cx| {
 9872                project.update(cx, |project, cx| {
 9873                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
 9874                });
 9875            })
 9876        }
 9877    }
 9878
 9879    fn cancel_language_server_work(
 9880        &mut self,
 9881        _: &CancelLanguageServerWork,
 9882        cx: &mut ViewContext<Self>,
 9883    ) {
 9884        if let Some(project) = self.project.clone() {
 9885            self.buffer.update(cx, |multi_buffer, cx| {
 9886                project.update(cx, |project, cx| {
 9887                    project.cancel_language_server_work_for_buffers(multi_buffer.all_buffers(), cx);
 9888                });
 9889            })
 9890        }
 9891    }
 9892
 9893    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
 9894        cx.show_character_palette();
 9895    }
 9896
 9897    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
 9898        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
 9899            let buffer = self.buffer.read(cx).snapshot(cx);
 9900            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
 9901            let is_valid = buffer
 9902                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
 9903                .any(|entry| {
 9904                    entry.diagnostic.is_primary
 9905                        && !entry.range.is_empty()
 9906                        && entry.range.start == primary_range_start
 9907                        && entry.diagnostic.message == active_diagnostics.primary_message
 9908                });
 9909
 9910            if is_valid != active_diagnostics.is_valid {
 9911                active_diagnostics.is_valid = is_valid;
 9912                let mut new_styles = HashMap::default();
 9913                for (block_id, diagnostic) in &active_diagnostics.blocks {
 9914                    new_styles.insert(
 9915                        *block_id,
 9916                        diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
 9917                    );
 9918                }
 9919                self.display_map.update(cx, |display_map, _cx| {
 9920                    display_map.replace_blocks(new_styles)
 9921                });
 9922            }
 9923        }
 9924    }
 9925
 9926    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
 9927        self.dismiss_diagnostics(cx);
 9928        let snapshot = self.snapshot(cx);
 9929        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
 9930            let buffer = self.buffer.read(cx).snapshot(cx);
 9931
 9932            let mut primary_range = None;
 9933            let mut primary_message = None;
 9934            let mut group_end = Point::zero();
 9935            let diagnostic_group = buffer
 9936                .diagnostic_group::<MultiBufferPoint>(group_id)
 9937                .filter_map(|entry| {
 9938                    if snapshot.is_line_folded(MultiBufferRow(entry.range.start.row))
 9939                        && (entry.range.start.row == entry.range.end.row
 9940                            || snapshot.is_line_folded(MultiBufferRow(entry.range.end.row)))
 9941                    {
 9942                        return None;
 9943                    }
 9944                    if entry.range.end > group_end {
 9945                        group_end = entry.range.end;
 9946                    }
 9947                    if entry.diagnostic.is_primary {
 9948                        primary_range = Some(entry.range.clone());
 9949                        primary_message = Some(entry.diagnostic.message.clone());
 9950                    }
 9951                    Some(entry)
 9952                })
 9953                .collect::<Vec<_>>();
 9954            let primary_range = primary_range?;
 9955            let primary_message = primary_message?;
 9956            let primary_range =
 9957                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
 9958
 9959            let blocks = display_map
 9960                .insert_blocks(
 9961                    diagnostic_group.iter().map(|entry| {
 9962                        let diagnostic = entry.diagnostic.clone();
 9963                        let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
 9964                        BlockProperties {
 9965                            style: BlockStyle::Fixed,
 9966                            position: buffer.anchor_after(entry.range.start),
 9967                            height: message_height,
 9968                            render: diagnostic_block_renderer(diagnostic, None, true, true),
 9969                            disposition: BlockDisposition::Below,
 9970                            priority: 0,
 9971                        }
 9972                    }),
 9973                    cx,
 9974                )
 9975                .into_iter()
 9976                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
 9977                .collect();
 9978
 9979            Some(ActiveDiagnosticGroup {
 9980                primary_range,
 9981                primary_message,
 9982                group_id,
 9983                blocks,
 9984                is_valid: true,
 9985            })
 9986        });
 9987        self.active_diagnostics.is_some()
 9988    }
 9989
 9990    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
 9991        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
 9992            self.display_map.update(cx, |display_map, cx| {
 9993                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
 9994            });
 9995            cx.notify();
 9996        }
 9997    }
 9998
 9999    pub fn set_selections_from_remote(
10000        &mut self,
10001        selections: Vec<Selection<Anchor>>,
10002        pending_selection: Option<Selection<Anchor>>,
10003        cx: &mut ViewContext<Self>,
10004    ) {
10005        let old_cursor_position = self.selections.newest_anchor().head();
10006        self.selections.change_with(cx, |s| {
10007            s.select_anchors(selections);
10008            if let Some(pending_selection) = pending_selection {
10009                s.set_pending(pending_selection, SelectMode::Character);
10010            } else {
10011                s.clear_pending();
10012            }
10013        });
10014        self.selections_did_change(false, &old_cursor_position, true, cx);
10015    }
10016
10017    fn push_to_selection_history(&mut self) {
10018        self.selection_history.push(SelectionHistoryEntry {
10019            selections: self.selections.disjoint_anchors(),
10020            select_next_state: self.select_next_state.clone(),
10021            select_prev_state: self.select_prev_state.clone(),
10022            add_selections_state: self.add_selections_state.clone(),
10023        });
10024    }
10025
10026    pub fn transact(
10027        &mut self,
10028        cx: &mut ViewContext<Self>,
10029        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
10030    ) -> Option<TransactionId> {
10031        self.start_transaction_at(Instant::now(), cx);
10032        update(self, cx);
10033        self.end_transaction_at(Instant::now(), cx)
10034    }
10035
10036    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
10037        self.end_selection(cx);
10038        if let Some(tx_id) = self
10039            .buffer
10040            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
10041        {
10042            self.selection_history
10043                .insert_transaction(tx_id, self.selections.disjoint_anchors());
10044            cx.emit(EditorEvent::TransactionBegun {
10045                transaction_id: tx_id,
10046            })
10047        }
10048    }
10049
10050    fn end_transaction_at(
10051        &mut self,
10052        now: Instant,
10053        cx: &mut ViewContext<Self>,
10054    ) -> Option<TransactionId> {
10055        if let Some(transaction_id) = self
10056            .buffer
10057            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
10058        {
10059            if let Some((_, end_selections)) =
10060                self.selection_history.transaction_mut(transaction_id)
10061            {
10062                *end_selections = Some(self.selections.disjoint_anchors());
10063            } else {
10064                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
10065            }
10066
10067            cx.emit(EditorEvent::Edited { transaction_id });
10068            Some(transaction_id)
10069        } else {
10070            None
10071        }
10072    }
10073
10074    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
10075        let mut fold_ranges = Vec::new();
10076
10077        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10078
10079        let selections = self.selections.all_adjusted(cx);
10080        for selection in selections {
10081            let range = selection.range().sorted();
10082            let buffer_start_row = range.start.row;
10083
10084            for row in (0..=range.end.row).rev() {
10085                if let Some((foldable_range, fold_text)) =
10086                    display_map.foldable_range(MultiBufferRow(row))
10087                {
10088                    if foldable_range.end.row >= buffer_start_row {
10089                        fold_ranges.push((foldable_range, fold_text));
10090                        if row <= range.start.row {
10091                            break;
10092                        }
10093                    }
10094                }
10095            }
10096        }
10097
10098        self.fold_ranges(fold_ranges, true, cx);
10099    }
10100
10101    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
10102        let buffer_row = fold_at.buffer_row;
10103        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10104
10105        if let Some((fold_range, placeholder)) = display_map.foldable_range(buffer_row) {
10106            let autoscroll = self
10107                .selections
10108                .all::<Point>(cx)
10109                .iter()
10110                .any(|selection| fold_range.overlaps(&selection.range()));
10111
10112            self.fold_ranges([(fold_range, placeholder)], autoscroll, cx);
10113        }
10114    }
10115
10116    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
10117        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10118        let buffer = &display_map.buffer_snapshot;
10119        let selections = self.selections.all::<Point>(cx);
10120        let ranges = selections
10121            .iter()
10122            .map(|s| {
10123                let range = s.display_range(&display_map).sorted();
10124                let mut start = range.start.to_point(&display_map);
10125                let mut end = range.end.to_point(&display_map);
10126                start.column = 0;
10127                end.column = buffer.line_len(MultiBufferRow(end.row));
10128                start..end
10129            })
10130            .collect::<Vec<_>>();
10131
10132        self.unfold_ranges(ranges, true, true, cx);
10133    }
10134
10135    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
10136        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10137
10138        let intersection_range = Point::new(unfold_at.buffer_row.0, 0)
10139            ..Point::new(
10140                unfold_at.buffer_row.0,
10141                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
10142            );
10143
10144        let autoscroll = self
10145            .selections
10146            .all::<Point>(cx)
10147            .iter()
10148            .any(|selection| selection.range().overlaps(&intersection_range));
10149
10150        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
10151    }
10152
10153    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
10154        let selections = self.selections.all::<Point>(cx);
10155        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10156        let line_mode = self.selections.line_mode;
10157        let ranges = selections.into_iter().map(|s| {
10158            if line_mode {
10159                let start = Point::new(s.start.row, 0);
10160                let end = Point::new(
10161                    s.end.row,
10162                    display_map
10163                        .buffer_snapshot
10164                        .line_len(MultiBufferRow(s.end.row)),
10165                );
10166                (start..end, display_map.fold_placeholder.clone())
10167            } else {
10168                (s.start..s.end, display_map.fold_placeholder.clone())
10169            }
10170        });
10171        self.fold_ranges(ranges, true, cx);
10172    }
10173
10174    pub fn fold_ranges<T: ToOffset + Clone>(
10175        &mut self,
10176        ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>,
10177        auto_scroll: bool,
10178        cx: &mut ViewContext<Self>,
10179    ) {
10180        let mut fold_ranges = Vec::new();
10181        let mut buffers_affected = HashMap::default();
10182        let multi_buffer = self.buffer().read(cx);
10183        for (fold_range, fold_text) in ranges {
10184            if let Some((_, buffer, _)) =
10185                multi_buffer.excerpt_containing(fold_range.start.clone(), cx)
10186            {
10187                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
10188            };
10189            fold_ranges.push((fold_range, fold_text));
10190        }
10191
10192        let mut ranges = fold_ranges.into_iter().peekable();
10193        if ranges.peek().is_some() {
10194            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
10195
10196            if auto_scroll {
10197                self.request_autoscroll(Autoscroll::fit(), cx);
10198            }
10199
10200            for buffer in buffers_affected.into_values() {
10201                self.sync_expanded_diff_hunks(buffer, cx);
10202            }
10203
10204            cx.notify();
10205
10206            if let Some(active_diagnostics) = self.active_diagnostics.take() {
10207                // Clear diagnostics block when folding a range that contains it.
10208                let snapshot = self.snapshot(cx);
10209                if snapshot.intersects_fold(active_diagnostics.primary_range.start) {
10210                    drop(snapshot);
10211                    self.active_diagnostics = Some(active_diagnostics);
10212                    self.dismiss_diagnostics(cx);
10213                } else {
10214                    self.active_diagnostics = Some(active_diagnostics);
10215                }
10216            }
10217
10218            self.scrollbar_marker_state.dirty = true;
10219        }
10220    }
10221
10222    pub fn unfold_ranges<T: ToOffset + Clone>(
10223        &mut self,
10224        ranges: impl IntoIterator<Item = Range<T>>,
10225        inclusive: bool,
10226        auto_scroll: bool,
10227        cx: &mut ViewContext<Self>,
10228    ) {
10229        let mut unfold_ranges = Vec::new();
10230        let mut buffers_affected = HashMap::default();
10231        let multi_buffer = self.buffer().read(cx);
10232        for range in ranges {
10233            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
10234                buffers_affected.insert(buffer.read(cx).remote_id(), buffer);
10235            };
10236            unfold_ranges.push(range);
10237        }
10238
10239        let mut ranges = unfold_ranges.into_iter().peekable();
10240        if ranges.peek().is_some() {
10241            self.display_map
10242                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
10243            if auto_scroll {
10244                self.request_autoscroll(Autoscroll::fit(), cx);
10245            }
10246
10247            for buffer in buffers_affected.into_values() {
10248                self.sync_expanded_diff_hunks(buffer, cx);
10249            }
10250
10251            cx.notify();
10252            self.scrollbar_marker_state.dirty = true;
10253            self.active_indent_guides_state.dirty = true;
10254        }
10255    }
10256
10257    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
10258        if hovered != self.gutter_hovered {
10259            self.gutter_hovered = hovered;
10260            cx.notify();
10261        }
10262    }
10263
10264    pub fn insert_blocks(
10265        &mut self,
10266        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
10267        autoscroll: Option<Autoscroll>,
10268        cx: &mut ViewContext<Self>,
10269    ) -> Vec<CustomBlockId> {
10270        let blocks = self
10271            .display_map
10272            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
10273        if let Some(autoscroll) = autoscroll {
10274            self.request_autoscroll(autoscroll, cx);
10275        }
10276        cx.notify();
10277        blocks
10278    }
10279
10280    pub fn resize_blocks(
10281        &mut self,
10282        heights: HashMap<CustomBlockId, u32>,
10283        autoscroll: Option<Autoscroll>,
10284        cx: &mut ViewContext<Self>,
10285    ) {
10286        self.display_map
10287            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
10288        if let Some(autoscroll) = autoscroll {
10289            self.request_autoscroll(autoscroll, cx);
10290        }
10291        cx.notify();
10292    }
10293
10294    pub fn replace_blocks(
10295        &mut self,
10296        renderers: HashMap<CustomBlockId, RenderBlock>,
10297        autoscroll: Option<Autoscroll>,
10298        cx: &mut ViewContext<Self>,
10299    ) {
10300        self.display_map
10301            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
10302        if let Some(autoscroll) = autoscroll {
10303            self.request_autoscroll(autoscroll, cx);
10304        }
10305        cx.notify();
10306    }
10307
10308    pub fn remove_blocks(
10309        &mut self,
10310        block_ids: HashSet<CustomBlockId>,
10311        autoscroll: Option<Autoscroll>,
10312        cx: &mut ViewContext<Self>,
10313    ) {
10314        self.display_map.update(cx, |display_map, cx| {
10315            display_map.remove_blocks(block_ids, cx)
10316        });
10317        if let Some(autoscroll) = autoscroll {
10318            self.request_autoscroll(autoscroll, cx);
10319        }
10320        cx.notify();
10321    }
10322
10323    pub fn row_for_block(
10324        &self,
10325        block_id: CustomBlockId,
10326        cx: &mut ViewContext<Self>,
10327    ) -> Option<DisplayRow> {
10328        self.display_map
10329            .update(cx, |map, cx| map.row_for_block(block_id, cx))
10330    }
10331
10332    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
10333        self.focused_block = Some(focused_block);
10334    }
10335
10336    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
10337        self.focused_block.take()
10338    }
10339
10340    pub fn insert_creases(
10341        &mut self,
10342        creases: impl IntoIterator<Item = Crease>,
10343        cx: &mut ViewContext<Self>,
10344    ) -> Vec<CreaseId> {
10345        self.display_map
10346            .update(cx, |map, cx| map.insert_creases(creases, cx))
10347    }
10348
10349    pub fn remove_creases(
10350        &mut self,
10351        ids: impl IntoIterator<Item = CreaseId>,
10352        cx: &mut ViewContext<Self>,
10353    ) {
10354        self.display_map
10355            .update(cx, |map, cx| map.remove_creases(ids, cx));
10356    }
10357
10358    pub fn longest_row(&self, cx: &mut AppContext) -> DisplayRow {
10359        self.display_map
10360            .update(cx, |map, cx| map.snapshot(cx))
10361            .longest_row()
10362    }
10363
10364    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
10365        self.display_map
10366            .update(cx, |map, cx| map.snapshot(cx))
10367            .max_point()
10368    }
10369
10370    pub fn text(&self, cx: &AppContext) -> String {
10371        self.buffer.read(cx).read(cx).text()
10372    }
10373
10374    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
10375        let text = self.text(cx);
10376        let text = text.trim();
10377
10378        if text.is_empty() {
10379            return None;
10380        }
10381
10382        Some(text.to_string())
10383    }
10384
10385    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
10386        self.transact(cx, |this, cx| {
10387            this.buffer
10388                .read(cx)
10389                .as_singleton()
10390                .expect("you can only call set_text on editors for singleton buffers")
10391                .update(cx, |buffer, cx| buffer.set_text(text, cx));
10392        });
10393    }
10394
10395    pub fn display_text(&self, cx: &mut AppContext) -> String {
10396        self.display_map
10397            .update(cx, |map, cx| map.snapshot(cx))
10398            .text()
10399    }
10400
10401    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
10402        let mut wrap_guides = smallvec::smallvec![];
10403
10404        if self.show_wrap_guides == Some(false) {
10405            return wrap_guides;
10406        }
10407
10408        let settings = self.buffer.read(cx).settings_at(0, cx);
10409        if settings.show_wrap_guides {
10410            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
10411                wrap_guides.push((soft_wrap as usize, true));
10412            }
10413            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
10414        }
10415
10416        wrap_guides
10417    }
10418
10419    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
10420        let settings = self.buffer.read(cx).settings_at(0, cx);
10421        let mode = self
10422            .soft_wrap_mode_override
10423            .unwrap_or_else(|| settings.soft_wrap);
10424        match mode {
10425            language_settings::SoftWrap::None => SoftWrap::None,
10426            language_settings::SoftWrap::PreferLine => SoftWrap::PreferLine,
10427            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
10428            language_settings::SoftWrap::PreferredLineLength => {
10429                SoftWrap::Column(settings.preferred_line_length)
10430            }
10431        }
10432    }
10433
10434    pub fn set_soft_wrap_mode(
10435        &mut self,
10436        mode: language_settings::SoftWrap,
10437        cx: &mut ViewContext<Self>,
10438    ) {
10439        self.soft_wrap_mode_override = Some(mode);
10440        cx.notify();
10441    }
10442
10443    pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
10444        let rem_size = cx.rem_size();
10445        self.display_map.update(cx, |map, cx| {
10446            map.set_font(
10447                style.text.font(),
10448                style.text.font_size.to_pixels(rem_size),
10449                cx,
10450            )
10451        });
10452        self.style = Some(style);
10453    }
10454
10455    pub fn style(&self) -> Option<&EditorStyle> {
10456        self.style.as_ref()
10457    }
10458
10459    // Called by the element. This method is not designed to be called outside of the editor
10460    // element's layout code because it does not notify when rewrapping is computed synchronously.
10461    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
10462        self.display_map
10463            .update(cx, |map, cx| map.set_wrap_width(width, cx))
10464    }
10465
10466    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
10467        if self.soft_wrap_mode_override.is_some() {
10468            self.soft_wrap_mode_override.take();
10469        } else {
10470            let soft_wrap = match self.soft_wrap_mode(cx) {
10471                SoftWrap::None | SoftWrap::PreferLine => language_settings::SoftWrap::EditorWidth,
10472                SoftWrap::EditorWidth | SoftWrap::Column(_) => {
10473                    language_settings::SoftWrap::PreferLine
10474                }
10475            };
10476            self.soft_wrap_mode_override = Some(soft_wrap);
10477        }
10478        cx.notify();
10479    }
10480
10481    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, cx: &mut ViewContext<Self>) {
10482        let Some(workspace) = self.workspace() else {
10483            return;
10484        };
10485        let fs = workspace.read(cx).app_state().fs.clone();
10486        let current_show = TabBarSettings::get_global(cx).show;
10487        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
10488            setting.show = Some(!current_show);
10489        });
10490    }
10491
10492    pub fn toggle_indent_guides(&mut self, _: &ToggleIndentGuides, cx: &mut ViewContext<Self>) {
10493        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
10494            self.buffer
10495                .read(cx)
10496                .settings_at(0, cx)
10497                .indent_guides
10498                .enabled
10499        });
10500        self.show_indent_guides = Some(!currently_enabled);
10501        cx.notify();
10502    }
10503
10504    fn should_show_indent_guides(&self) -> Option<bool> {
10505        self.show_indent_guides
10506    }
10507
10508    pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext<Self>) {
10509        let mut editor_settings = EditorSettings::get_global(cx).clone();
10510        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
10511        EditorSettings::override_global(editor_settings, cx);
10512    }
10513
10514    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
10515        self.show_gutter = show_gutter;
10516        cx.notify();
10517    }
10518
10519    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut ViewContext<Self>) {
10520        self.show_line_numbers = Some(show_line_numbers);
10521        cx.notify();
10522    }
10523
10524    pub fn set_show_git_diff_gutter(
10525        &mut self,
10526        show_git_diff_gutter: bool,
10527        cx: &mut ViewContext<Self>,
10528    ) {
10529        self.show_git_diff_gutter = Some(show_git_diff_gutter);
10530        cx.notify();
10531    }
10532
10533    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut ViewContext<Self>) {
10534        self.show_code_actions = Some(show_code_actions);
10535        cx.notify();
10536    }
10537
10538    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut ViewContext<Self>) {
10539        self.show_runnables = Some(show_runnables);
10540        cx.notify();
10541    }
10542
10543    pub fn set_masked(&mut self, masked: bool, cx: &mut ViewContext<Self>) {
10544        if self.display_map.read(cx).masked != masked {
10545            self.display_map.update(cx, |map, _| map.masked = masked);
10546        }
10547        cx.notify()
10548    }
10549
10550    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut ViewContext<Self>) {
10551        self.show_wrap_guides = Some(show_wrap_guides);
10552        cx.notify();
10553    }
10554
10555    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut ViewContext<Self>) {
10556        self.show_indent_guides = Some(show_indent_guides);
10557        cx.notify();
10558    }
10559
10560    pub fn working_directory(&self, cx: &WindowContext) -> Option<PathBuf> {
10561        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
10562            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
10563                if let Some(dir) = file.abs_path(cx).parent() {
10564                    return Some(dir.to_owned());
10565                }
10566            }
10567
10568            if let Some(project_path) = buffer.read(cx).project_path(cx) {
10569                return Some(project_path.path.to_path_buf());
10570            }
10571        }
10572
10573        None
10574    }
10575
10576    pub fn reveal_in_finder(&mut self, _: &RevealInFileManager, cx: &mut ViewContext<Self>) {
10577        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
10578            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
10579                cx.reveal_path(&file.abs_path(cx));
10580            }
10581        }
10582    }
10583
10584    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
10585        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
10586            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
10587                if let Some(path) = file.abs_path(cx).to_str() {
10588                    cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
10589                }
10590            }
10591        }
10592    }
10593
10594    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
10595        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
10596            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
10597                if let Some(path) = file.path().to_str() {
10598                    cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
10599                }
10600            }
10601        }
10602    }
10603
10604    pub fn toggle_git_blame(&mut self, _: &ToggleGitBlame, cx: &mut ViewContext<Self>) {
10605        self.show_git_blame_gutter = !self.show_git_blame_gutter;
10606
10607        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
10608            self.start_git_blame(true, cx);
10609        }
10610
10611        cx.notify();
10612    }
10613
10614    pub fn toggle_git_blame_inline(
10615        &mut self,
10616        _: &ToggleGitBlameInline,
10617        cx: &mut ViewContext<Self>,
10618    ) {
10619        self.toggle_git_blame_inline_internal(true, cx);
10620        cx.notify();
10621    }
10622
10623    pub fn git_blame_inline_enabled(&self) -> bool {
10624        self.git_blame_inline_enabled
10625    }
10626
10627    pub fn toggle_selection_menu(&mut self, _: &ToggleSelectionMenu, cx: &mut ViewContext<Self>) {
10628        self.show_selection_menu = self
10629            .show_selection_menu
10630            .map(|show_selections_menu| !show_selections_menu)
10631            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
10632
10633        cx.notify();
10634    }
10635
10636    pub fn selection_menu_enabled(&self, cx: &AppContext) -> bool {
10637        self.show_selection_menu
10638            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
10639    }
10640
10641    fn start_git_blame(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
10642        if let Some(project) = self.project.as_ref() {
10643            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
10644                return;
10645            };
10646
10647            if buffer.read(cx).file().is_none() {
10648                return;
10649            }
10650
10651            let focused = self.focus_handle(cx).contains_focused(cx);
10652
10653            let project = project.clone();
10654            let blame =
10655                cx.new_model(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
10656            self.blame_subscription = Some(cx.observe(&blame, |_, _, cx| cx.notify()));
10657            self.blame = Some(blame);
10658        }
10659    }
10660
10661    fn toggle_git_blame_inline_internal(
10662        &mut self,
10663        user_triggered: bool,
10664        cx: &mut ViewContext<Self>,
10665    ) {
10666        if self.git_blame_inline_enabled {
10667            self.git_blame_inline_enabled = false;
10668            self.show_git_blame_inline = false;
10669            self.show_git_blame_inline_delay_task.take();
10670        } else {
10671            self.git_blame_inline_enabled = true;
10672            self.start_git_blame_inline(user_triggered, cx);
10673        }
10674
10675        cx.notify();
10676    }
10677
10678    fn start_git_blame_inline(&mut self, user_triggered: bool, cx: &mut ViewContext<Self>) {
10679        self.start_git_blame(user_triggered, cx);
10680
10681        if ProjectSettings::get_global(cx)
10682            .git
10683            .inline_blame_delay()
10684            .is_some()
10685        {
10686            self.start_inline_blame_timer(cx);
10687        } else {
10688            self.show_git_blame_inline = true
10689        }
10690    }
10691
10692    pub fn blame(&self) -> Option<&Model<GitBlame>> {
10693        self.blame.as_ref()
10694    }
10695
10696    pub fn render_git_blame_gutter(&mut self, cx: &mut WindowContext) -> bool {
10697        self.show_git_blame_gutter && self.has_blame_entries(cx)
10698    }
10699
10700    pub fn render_git_blame_inline(&mut self, cx: &mut WindowContext) -> bool {
10701        self.show_git_blame_inline
10702            && self.focus_handle.is_focused(cx)
10703            && !self.newest_selection_head_on_empty_line(cx)
10704            && self.has_blame_entries(cx)
10705    }
10706
10707    fn has_blame_entries(&self, cx: &mut WindowContext) -> bool {
10708        self.blame()
10709            .map_or(false, |blame| blame.read(cx).has_generated_entries())
10710    }
10711
10712    fn newest_selection_head_on_empty_line(&mut self, cx: &mut WindowContext) -> bool {
10713        let cursor_anchor = self.selections.newest_anchor().head();
10714
10715        let snapshot = self.buffer.read(cx).snapshot(cx);
10716        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
10717
10718        snapshot.line_len(buffer_row) == 0
10719    }
10720
10721    fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Result<url::Url> {
10722        let (path, selection, repo) = maybe!({
10723            let project_handle = self.project.as_ref()?.clone();
10724            let project = project_handle.read(cx);
10725
10726            let selection = self.selections.newest::<Point>(cx);
10727            let selection_range = selection.range();
10728
10729            let (buffer, selection) = if let Some(buffer) = self.buffer().read(cx).as_singleton() {
10730                (buffer, selection_range.start.row..selection_range.end.row)
10731            } else {
10732                let buffer_ranges = self
10733                    .buffer()
10734                    .read(cx)
10735                    .range_to_buffer_ranges(selection_range, cx);
10736
10737                let (buffer, range, _) = if selection.reversed {
10738                    buffer_ranges.first()
10739                } else {
10740                    buffer_ranges.last()
10741                }?;
10742
10743                let snapshot = buffer.read(cx).snapshot();
10744                let selection = text::ToPoint::to_point(&range.start, &snapshot).row
10745                    ..text::ToPoint::to_point(&range.end, &snapshot).row;
10746                (buffer.clone(), selection)
10747            };
10748
10749            let path = buffer
10750                .read(cx)
10751                .file()?
10752                .as_local()?
10753                .path()
10754                .to_str()?
10755                .to_string();
10756            let repo = project.get_repo(&buffer.read(cx).project_path(cx)?, cx)?;
10757            Some((path, selection, repo))
10758        })
10759        .ok_or_else(|| anyhow!("unable to open git repository"))?;
10760
10761        const REMOTE_NAME: &str = "origin";
10762        let origin_url = repo
10763            .remote_url(REMOTE_NAME)
10764            .ok_or_else(|| anyhow!("remote \"{REMOTE_NAME}\" not found"))?;
10765        let sha = repo
10766            .head_sha()
10767            .ok_or_else(|| anyhow!("failed to read HEAD SHA"))?;
10768
10769        let (provider, remote) =
10770            parse_git_remote_url(GitHostingProviderRegistry::default_global(cx), &origin_url)
10771                .ok_or_else(|| anyhow!("failed to parse Git remote URL"))?;
10772
10773        Ok(provider.build_permalink(
10774            remote,
10775            BuildPermalinkParams {
10776                sha: &sha,
10777                path: &path,
10778                selection: Some(selection),
10779            },
10780        ))
10781    }
10782
10783    pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
10784        let permalink = self.get_permalink_to_line(cx);
10785
10786        match permalink {
10787            Ok(permalink) => {
10788                cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
10789            }
10790            Err(err) => {
10791                let message = format!("Failed to copy permalink: {err}");
10792
10793                Err::<(), anyhow::Error>(err).log_err();
10794
10795                if let Some(workspace) = self.workspace() {
10796                    workspace.update(cx, |workspace, cx| {
10797                        struct CopyPermalinkToLine;
10798
10799                        workspace.show_toast(
10800                            Toast::new(NotificationId::unique::<CopyPermalinkToLine>(), message),
10801                            cx,
10802                        )
10803                    })
10804                }
10805            }
10806        }
10807    }
10808
10809    pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
10810        let permalink = self.get_permalink_to_line(cx);
10811
10812        match permalink {
10813            Ok(permalink) => {
10814                cx.open_url(permalink.as_ref());
10815            }
10816            Err(err) => {
10817                let message = format!("Failed to open permalink: {err}");
10818
10819                Err::<(), anyhow::Error>(err).log_err();
10820
10821                if let Some(workspace) = self.workspace() {
10822                    workspace.update(cx, |workspace, cx| {
10823                        struct OpenPermalinkToLine;
10824
10825                        workspace.show_toast(
10826                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
10827                            cx,
10828                        )
10829                    })
10830                }
10831            }
10832        }
10833    }
10834
10835    /// Adds or removes (on `None` color) a highlight for the rows corresponding to the anchor range given.
10836    /// On matching anchor range, replaces the old highlight; does not clear the other existing highlights.
10837    /// If multiple anchor ranges will produce highlights for the same row, the last range added will be used.
10838    pub fn highlight_rows<T: 'static>(
10839        &mut self,
10840        rows: RangeInclusive<Anchor>,
10841        color: Option<Hsla>,
10842        should_autoscroll: bool,
10843        cx: &mut ViewContext<Self>,
10844    ) {
10845        let snapshot = self.buffer().read(cx).snapshot(cx);
10846        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
10847        let existing_highlight_index = row_highlights.binary_search_by(|highlight| {
10848            highlight
10849                .range
10850                .start()
10851                .cmp(&rows.start(), &snapshot)
10852                .then(highlight.range.end().cmp(&rows.end(), &snapshot))
10853        });
10854        match (color, existing_highlight_index) {
10855            (Some(_), Ok(ix)) | (_, Err(ix)) => row_highlights.insert(
10856                ix,
10857                RowHighlight {
10858                    index: post_inc(&mut self.highlight_order),
10859                    range: rows,
10860                    should_autoscroll,
10861                    color,
10862                },
10863            ),
10864            (None, Ok(i)) => {
10865                row_highlights.remove(i);
10866            }
10867        }
10868    }
10869
10870    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
10871    pub fn clear_row_highlights<T: 'static>(&mut self) {
10872        self.highlighted_rows.remove(&TypeId::of::<T>());
10873    }
10874
10875    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
10876    pub fn highlighted_rows<T: 'static>(
10877        &self,
10878    ) -> Option<impl Iterator<Item = (&RangeInclusive<Anchor>, Option<&Hsla>)>> {
10879        Some(
10880            self.highlighted_rows
10881                .get(&TypeId::of::<T>())?
10882                .iter()
10883                .map(|highlight| (&highlight.range, highlight.color.as_ref())),
10884        )
10885    }
10886
10887    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
10888    /// Rerturns a map of display rows that are highlighted and their corresponding highlight color.
10889    /// Allows to ignore certain kinds of highlights.
10890    pub fn highlighted_display_rows(
10891        &mut self,
10892        cx: &mut WindowContext,
10893    ) -> BTreeMap<DisplayRow, Hsla> {
10894        let snapshot = self.snapshot(cx);
10895        let mut used_highlight_orders = HashMap::default();
10896        self.highlighted_rows
10897            .iter()
10898            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
10899            .fold(
10900                BTreeMap::<DisplayRow, Hsla>::new(),
10901                |mut unique_rows, highlight| {
10902                    let start_row = highlight.range.start().to_display_point(&snapshot).row();
10903                    let end_row = highlight.range.end().to_display_point(&snapshot).row();
10904                    for row in start_row.0..=end_row.0 {
10905                        let used_index =
10906                            used_highlight_orders.entry(row).or_insert(highlight.index);
10907                        if highlight.index >= *used_index {
10908                            *used_index = highlight.index;
10909                            match highlight.color {
10910                                Some(hsla) => unique_rows.insert(DisplayRow(row), hsla),
10911                                None => unique_rows.remove(&DisplayRow(row)),
10912                            };
10913                        }
10914                    }
10915                    unique_rows
10916                },
10917            )
10918    }
10919
10920    pub fn highlighted_display_row_for_autoscroll(
10921        &self,
10922        snapshot: &DisplaySnapshot,
10923    ) -> Option<DisplayRow> {
10924        self.highlighted_rows
10925            .values()
10926            .flat_map(|highlighted_rows| highlighted_rows.iter())
10927            .filter_map(|highlight| {
10928                if highlight.color.is_none() || !highlight.should_autoscroll {
10929                    return None;
10930                }
10931                Some(highlight.range.start().to_display_point(&snapshot).row())
10932            })
10933            .min()
10934    }
10935
10936    pub fn set_search_within_ranges(
10937        &mut self,
10938        ranges: &[Range<Anchor>],
10939        cx: &mut ViewContext<Self>,
10940    ) {
10941        self.highlight_background::<SearchWithinRange>(
10942            ranges,
10943            |colors| colors.editor_document_highlight_read_background,
10944            cx,
10945        )
10946    }
10947
10948    pub fn set_breadcrumb_header(&mut self, new_header: String) {
10949        self.breadcrumb_header = Some(new_header);
10950    }
10951
10952    pub fn clear_search_within_ranges(&mut self, cx: &mut ViewContext<Self>) {
10953        self.clear_background_highlights::<SearchWithinRange>(cx);
10954    }
10955
10956    pub fn highlight_background<T: 'static>(
10957        &mut self,
10958        ranges: &[Range<Anchor>],
10959        color_fetcher: fn(&ThemeColors) -> Hsla,
10960        cx: &mut ViewContext<Self>,
10961    ) {
10962        self.background_highlights
10963            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
10964        self.scrollbar_marker_state.dirty = true;
10965        cx.notify();
10966    }
10967
10968    pub fn clear_background_highlights<T: 'static>(
10969        &mut self,
10970        cx: &mut ViewContext<Self>,
10971    ) -> Option<BackgroundHighlight> {
10972        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
10973        if !text_highlights.1.is_empty() {
10974            self.scrollbar_marker_state.dirty = true;
10975            cx.notify();
10976        }
10977        Some(text_highlights)
10978    }
10979
10980    pub fn highlight_gutter<T: 'static>(
10981        &mut self,
10982        ranges: &[Range<Anchor>],
10983        color_fetcher: fn(&AppContext) -> Hsla,
10984        cx: &mut ViewContext<Self>,
10985    ) {
10986        self.gutter_highlights
10987            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
10988        cx.notify();
10989    }
10990
10991    pub fn clear_gutter_highlights<T: 'static>(
10992        &mut self,
10993        cx: &mut ViewContext<Self>,
10994    ) -> Option<GutterHighlight> {
10995        cx.notify();
10996        self.gutter_highlights.remove(&TypeId::of::<T>())
10997    }
10998
10999    #[cfg(feature = "test-support")]
11000    pub fn all_text_background_highlights(
11001        &mut self,
11002        cx: &mut ViewContext<Self>,
11003    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
11004        let snapshot = self.snapshot(cx);
11005        let buffer = &snapshot.buffer_snapshot;
11006        let start = buffer.anchor_before(0);
11007        let end = buffer.anchor_after(buffer.len());
11008        let theme = cx.theme().colors();
11009        self.background_highlights_in_range(start..end, &snapshot, theme)
11010    }
11011
11012    #[cfg(feature = "test-support")]
11013    pub fn search_background_highlights(
11014        &mut self,
11015        cx: &mut ViewContext<Self>,
11016    ) -> Vec<Range<Point>> {
11017        let snapshot = self.buffer().read(cx).snapshot(cx);
11018
11019        let highlights = self
11020            .background_highlights
11021            .get(&TypeId::of::<items::BufferSearchHighlights>());
11022
11023        if let Some((_color, ranges)) = highlights {
11024            ranges
11025                .iter()
11026                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
11027                .collect_vec()
11028        } else {
11029            vec![]
11030        }
11031    }
11032
11033    fn document_highlights_for_position<'a>(
11034        &'a self,
11035        position: Anchor,
11036        buffer: &'a MultiBufferSnapshot,
11037    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
11038        let read_highlights = self
11039            .background_highlights
11040            .get(&TypeId::of::<DocumentHighlightRead>())
11041            .map(|h| &h.1);
11042        let write_highlights = self
11043            .background_highlights
11044            .get(&TypeId::of::<DocumentHighlightWrite>())
11045            .map(|h| &h.1);
11046        let left_position = position.bias_left(buffer);
11047        let right_position = position.bias_right(buffer);
11048        read_highlights
11049            .into_iter()
11050            .chain(write_highlights)
11051            .flat_map(move |ranges| {
11052                let start_ix = match ranges.binary_search_by(|probe| {
11053                    let cmp = probe.end.cmp(&left_position, buffer);
11054                    if cmp.is_ge() {
11055                        Ordering::Greater
11056                    } else {
11057                        Ordering::Less
11058                    }
11059                }) {
11060                    Ok(i) | Err(i) => i,
11061                };
11062
11063                ranges[start_ix..]
11064                    .iter()
11065                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
11066            })
11067    }
11068
11069    pub fn has_background_highlights<T: 'static>(&self) -> bool {
11070        self.background_highlights
11071            .get(&TypeId::of::<T>())
11072            .map_or(false, |(_, highlights)| !highlights.is_empty())
11073    }
11074
11075    pub fn background_highlights_in_range(
11076        &self,
11077        search_range: Range<Anchor>,
11078        display_snapshot: &DisplaySnapshot,
11079        theme: &ThemeColors,
11080    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
11081        let mut results = Vec::new();
11082        for (color_fetcher, ranges) in self.background_highlights.values() {
11083            let color = color_fetcher(theme);
11084            let start_ix = match ranges.binary_search_by(|probe| {
11085                let cmp = probe
11086                    .end
11087                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
11088                if cmp.is_gt() {
11089                    Ordering::Greater
11090                } else {
11091                    Ordering::Less
11092                }
11093            }) {
11094                Ok(i) | Err(i) => i,
11095            };
11096            for range in &ranges[start_ix..] {
11097                if range
11098                    .start
11099                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
11100                    .is_ge()
11101                {
11102                    break;
11103                }
11104
11105                let start = range.start.to_display_point(&display_snapshot);
11106                let end = range.end.to_display_point(&display_snapshot);
11107                results.push((start..end, color))
11108            }
11109        }
11110        results
11111    }
11112
11113    pub fn background_highlight_row_ranges<T: 'static>(
11114        &self,
11115        search_range: Range<Anchor>,
11116        display_snapshot: &DisplaySnapshot,
11117        count: usize,
11118    ) -> Vec<RangeInclusive<DisplayPoint>> {
11119        let mut results = Vec::new();
11120        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
11121            return vec![];
11122        };
11123
11124        let start_ix = match ranges.binary_search_by(|probe| {
11125            let cmp = probe
11126                .end
11127                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
11128            if cmp.is_gt() {
11129                Ordering::Greater
11130            } else {
11131                Ordering::Less
11132            }
11133        }) {
11134            Ok(i) | Err(i) => i,
11135        };
11136        let mut push_region = |start: Option<Point>, end: Option<Point>| {
11137            if let (Some(start_display), Some(end_display)) = (start, end) {
11138                results.push(
11139                    start_display.to_display_point(display_snapshot)
11140                        ..=end_display.to_display_point(display_snapshot),
11141                );
11142            }
11143        };
11144        let mut start_row: Option<Point> = None;
11145        let mut end_row: Option<Point> = None;
11146        if ranges.len() > count {
11147            return Vec::new();
11148        }
11149        for range in &ranges[start_ix..] {
11150            if range
11151                .start
11152                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
11153                .is_ge()
11154            {
11155                break;
11156            }
11157            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
11158            if let Some(current_row) = &end_row {
11159                if end.row == current_row.row {
11160                    continue;
11161                }
11162            }
11163            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
11164            if start_row.is_none() {
11165                assert_eq!(end_row, None);
11166                start_row = Some(start);
11167                end_row = Some(end);
11168                continue;
11169            }
11170            if let Some(current_end) = end_row.as_mut() {
11171                if start.row > current_end.row + 1 {
11172                    push_region(start_row, end_row);
11173                    start_row = Some(start);
11174                    end_row = Some(end);
11175                } else {
11176                    // Merge two hunks.
11177                    *current_end = end;
11178                }
11179            } else {
11180                unreachable!();
11181            }
11182        }
11183        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
11184        push_region(start_row, end_row);
11185        results
11186    }
11187
11188    pub fn gutter_highlights_in_range(
11189        &self,
11190        search_range: Range<Anchor>,
11191        display_snapshot: &DisplaySnapshot,
11192        cx: &AppContext,
11193    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
11194        let mut results = Vec::new();
11195        for (color_fetcher, ranges) in self.gutter_highlights.values() {
11196            let color = color_fetcher(cx);
11197            let start_ix = match ranges.binary_search_by(|probe| {
11198                let cmp = probe
11199                    .end
11200                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
11201                if cmp.is_gt() {
11202                    Ordering::Greater
11203                } else {
11204                    Ordering::Less
11205                }
11206            }) {
11207                Ok(i) | Err(i) => i,
11208            };
11209            for range in &ranges[start_ix..] {
11210                if range
11211                    .start
11212                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
11213                    .is_ge()
11214                {
11215                    break;
11216                }
11217
11218                let start = range.start.to_display_point(&display_snapshot);
11219                let end = range.end.to_display_point(&display_snapshot);
11220                results.push((start..end, color))
11221            }
11222        }
11223        results
11224    }
11225
11226    /// Get the text ranges corresponding to the redaction query
11227    pub fn redacted_ranges(
11228        &self,
11229        search_range: Range<Anchor>,
11230        display_snapshot: &DisplaySnapshot,
11231        cx: &WindowContext,
11232    ) -> Vec<Range<DisplayPoint>> {
11233        display_snapshot
11234            .buffer_snapshot
11235            .redacted_ranges(search_range, |file| {
11236                if let Some(file) = file {
11237                    file.is_private()
11238                        && EditorSettings::get(Some(file.as_ref().into()), cx).redact_private_values
11239                } else {
11240                    false
11241                }
11242            })
11243            .map(|range| {
11244                range.start.to_display_point(display_snapshot)
11245                    ..range.end.to_display_point(display_snapshot)
11246            })
11247            .collect()
11248    }
11249
11250    pub fn highlight_text<T: 'static>(
11251        &mut self,
11252        ranges: Vec<Range<Anchor>>,
11253        style: HighlightStyle,
11254        cx: &mut ViewContext<Self>,
11255    ) {
11256        self.display_map.update(cx, |map, _| {
11257            map.highlight_text(TypeId::of::<T>(), ranges, style)
11258        });
11259        cx.notify();
11260    }
11261
11262    pub(crate) fn highlight_inlays<T: 'static>(
11263        &mut self,
11264        highlights: Vec<InlayHighlight>,
11265        style: HighlightStyle,
11266        cx: &mut ViewContext<Self>,
11267    ) {
11268        self.display_map.update(cx, |map, _| {
11269            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
11270        });
11271        cx.notify();
11272    }
11273
11274    pub fn text_highlights<'a, T: 'static>(
11275        &'a self,
11276        cx: &'a AppContext,
11277    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
11278        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
11279    }
11280
11281    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
11282        let cleared = self
11283            .display_map
11284            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
11285        if cleared {
11286            cx.notify();
11287        }
11288    }
11289
11290    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
11291        (self.read_only(cx) || self.blink_manager.read(cx).visible())
11292            && self.focus_handle.is_focused(cx)
11293    }
11294
11295    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut ViewContext<Self>) {
11296        self.show_cursor_when_unfocused = is_enabled;
11297        cx.notify();
11298    }
11299
11300    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
11301        cx.notify();
11302    }
11303
11304    fn on_buffer_event(
11305        &mut self,
11306        multibuffer: Model<MultiBuffer>,
11307        event: &multi_buffer::Event,
11308        cx: &mut ViewContext<Self>,
11309    ) {
11310        match event {
11311            multi_buffer::Event::Edited {
11312                singleton_buffer_edited,
11313            } => {
11314                self.scrollbar_marker_state.dirty = true;
11315                self.active_indent_guides_state.dirty = true;
11316                self.refresh_active_diagnostics(cx);
11317                self.refresh_code_actions(cx);
11318                if self.has_active_inline_completion(cx) {
11319                    self.update_visible_inline_completion(cx);
11320                }
11321                cx.emit(EditorEvent::BufferEdited);
11322                cx.emit(SearchEvent::MatchesInvalidated);
11323                if *singleton_buffer_edited {
11324                    if let Some(project) = &self.project {
11325                        let project = project.read(cx);
11326                        #[allow(clippy::mutable_key_type)]
11327                        let languages_affected = multibuffer
11328                            .read(cx)
11329                            .all_buffers()
11330                            .into_iter()
11331                            .filter_map(|buffer| {
11332                                let buffer = buffer.read(cx);
11333                                let language = buffer.language()?;
11334                                if project.is_local()
11335                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
11336                                {
11337                                    None
11338                                } else {
11339                                    Some(language)
11340                                }
11341                            })
11342                            .cloned()
11343                            .collect::<HashSet<_>>();
11344                        if !languages_affected.is_empty() {
11345                            self.refresh_inlay_hints(
11346                                InlayHintRefreshReason::BufferEdited(languages_affected),
11347                                cx,
11348                            );
11349                        }
11350                    }
11351                }
11352
11353                let Some(project) = &self.project else { return };
11354                let telemetry = project.read(cx).client().telemetry().clone();
11355                refresh_linked_ranges(self, cx);
11356                telemetry.log_edit_event("editor");
11357            }
11358            multi_buffer::Event::ExcerptsAdded {
11359                buffer,
11360                predecessor,
11361                excerpts,
11362            } => {
11363                self.tasks_update_task = Some(self.refresh_runnables(cx));
11364                cx.emit(EditorEvent::ExcerptsAdded {
11365                    buffer: buffer.clone(),
11366                    predecessor: *predecessor,
11367                    excerpts: excerpts.clone(),
11368                });
11369                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
11370            }
11371            multi_buffer::Event::ExcerptsRemoved { ids } => {
11372                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
11373                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
11374            }
11375            multi_buffer::Event::ExcerptsEdited { ids } => {
11376                cx.emit(EditorEvent::ExcerptsEdited { ids: ids.clone() })
11377            }
11378            multi_buffer::Event::ExcerptsExpanded { ids } => {
11379                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
11380            }
11381            multi_buffer::Event::Reparsed(buffer_id) => {
11382                self.tasks_update_task = Some(self.refresh_runnables(cx));
11383
11384                cx.emit(EditorEvent::Reparsed(*buffer_id));
11385            }
11386            multi_buffer::Event::LanguageChanged(buffer_id) => {
11387                linked_editing_ranges::refresh_linked_ranges(self, cx);
11388                cx.emit(EditorEvent::Reparsed(*buffer_id));
11389                cx.notify();
11390            }
11391            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
11392            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
11393            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
11394                cx.emit(EditorEvent::TitleChanged)
11395            }
11396            multi_buffer::Event::DiffBaseChanged => {
11397                self.scrollbar_marker_state.dirty = true;
11398                cx.emit(EditorEvent::DiffBaseChanged);
11399                cx.notify();
11400            }
11401            multi_buffer::Event::DiffUpdated { buffer } => {
11402                self.sync_expanded_diff_hunks(buffer.clone(), cx);
11403                cx.notify();
11404            }
11405            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
11406            multi_buffer::Event::DiagnosticsUpdated => {
11407                self.refresh_active_diagnostics(cx);
11408                self.scrollbar_marker_state.dirty = true;
11409                cx.notify();
11410            }
11411            _ => {}
11412        };
11413    }
11414
11415    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
11416        cx.notify();
11417    }
11418
11419    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
11420        self.tasks_update_task = Some(self.refresh_runnables(cx));
11421        self.refresh_inline_completion(true, cx);
11422        self.refresh_inlay_hints(
11423            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
11424                self.selections.newest_anchor().head(),
11425                &self.buffer.read(cx).snapshot(cx),
11426                cx,
11427            )),
11428            cx,
11429        );
11430        let editor_settings = EditorSettings::get_global(cx);
11431        self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
11432        self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
11433
11434        let project_settings = ProjectSettings::get_global(cx);
11435        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
11436
11437        if self.mode == EditorMode::Full {
11438            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
11439            if self.git_blame_inline_enabled != inline_blame_enabled {
11440                self.toggle_git_blame_inline_internal(false, cx);
11441            }
11442        }
11443
11444        cx.notify();
11445    }
11446
11447    pub fn set_searchable(&mut self, searchable: bool) {
11448        self.searchable = searchable;
11449    }
11450
11451    pub fn searchable(&self) -> bool {
11452        self.searchable
11453    }
11454
11455    fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
11456        self.open_excerpts_common(true, cx)
11457    }
11458
11459    fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
11460        self.open_excerpts_common(false, cx)
11461    }
11462
11463    fn open_excerpts_common(&mut self, split: bool, cx: &mut ViewContext<Self>) {
11464        let buffer = self.buffer.read(cx);
11465        if buffer.is_singleton() {
11466            cx.propagate();
11467            return;
11468        }
11469
11470        let Some(workspace) = self.workspace() else {
11471            cx.propagate();
11472            return;
11473        };
11474
11475        let mut new_selections_by_buffer = HashMap::default();
11476        for selection in self.selections.all::<usize>(cx) {
11477            for (buffer, mut range, _) in
11478                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
11479            {
11480                if selection.reversed {
11481                    mem::swap(&mut range.start, &mut range.end);
11482                }
11483                new_selections_by_buffer
11484                    .entry(buffer)
11485                    .or_insert(Vec::new())
11486                    .push(range)
11487            }
11488        }
11489
11490        // We defer the pane interaction because we ourselves are a workspace item
11491        // and activating a new item causes the pane to call a method on us reentrantly,
11492        // which panics if we're on the stack.
11493        cx.window_context().defer(move |cx| {
11494            workspace.update(cx, |workspace, cx| {
11495                let pane = if split {
11496                    workspace.adjacent_pane(cx)
11497                } else {
11498                    workspace.active_pane().clone()
11499                };
11500
11501                for (buffer, ranges) in new_selections_by_buffer {
11502                    let editor =
11503                        workspace.open_project_item::<Self>(pane.clone(), buffer, true, true, cx);
11504                    editor.update(cx, |editor, cx| {
11505                        editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
11506                            s.select_ranges(ranges);
11507                        });
11508                    });
11509                }
11510            })
11511        });
11512    }
11513
11514    fn jump(
11515        &mut self,
11516        path: ProjectPath,
11517        position: Point,
11518        anchor: language::Anchor,
11519        offset_from_top: u32,
11520        cx: &mut ViewContext<Self>,
11521    ) {
11522        let workspace = self.workspace();
11523        cx.spawn(|_, mut cx| async move {
11524            let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
11525            let editor = workspace.update(&mut cx, |workspace, cx| {
11526                // Reset the preview item id before opening the new item
11527                workspace.active_pane().update(cx, |pane, cx| {
11528                    pane.set_preview_item_id(None, cx);
11529                });
11530                workspace.open_path_preview(path, None, true, true, cx)
11531            })?;
11532            let editor = editor
11533                .await?
11534                .downcast::<Editor>()
11535                .ok_or_else(|| anyhow!("opened item was not an editor"))?
11536                .downgrade();
11537            editor.update(&mut cx, |editor, cx| {
11538                let buffer = editor
11539                    .buffer()
11540                    .read(cx)
11541                    .as_singleton()
11542                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
11543                let buffer = buffer.read(cx);
11544                let cursor = if buffer.can_resolve(&anchor) {
11545                    language::ToPoint::to_point(&anchor, buffer)
11546                } else {
11547                    buffer.clip_point(position, Bias::Left)
11548                };
11549
11550                let nav_history = editor.nav_history.take();
11551                editor.change_selections(
11552                    Some(Autoscroll::top_relative(offset_from_top as usize)),
11553                    cx,
11554                    |s| {
11555                        s.select_ranges([cursor..cursor]);
11556                    },
11557                );
11558                editor.nav_history = nav_history;
11559
11560                anyhow::Ok(())
11561            })??;
11562
11563            anyhow::Ok(())
11564        })
11565        .detach_and_log_err(cx);
11566    }
11567
11568    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
11569        let snapshot = self.buffer.read(cx).read(cx);
11570        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
11571        Some(
11572            ranges
11573                .iter()
11574                .map(move |range| {
11575                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
11576                })
11577                .collect(),
11578        )
11579    }
11580
11581    fn selection_replacement_ranges(
11582        &self,
11583        range: Range<OffsetUtf16>,
11584        cx: &AppContext,
11585    ) -> Vec<Range<OffsetUtf16>> {
11586        let selections = self.selections.all::<OffsetUtf16>(cx);
11587        let newest_selection = selections
11588            .iter()
11589            .max_by_key(|selection| selection.id)
11590            .unwrap();
11591        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
11592        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
11593        let snapshot = self.buffer.read(cx).read(cx);
11594        selections
11595            .into_iter()
11596            .map(|mut selection| {
11597                selection.start.0 =
11598                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
11599                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
11600                snapshot.clip_offset_utf16(selection.start, Bias::Left)
11601                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
11602            })
11603            .collect()
11604    }
11605
11606    fn report_editor_event(
11607        &self,
11608        operation: &'static str,
11609        file_extension: Option<String>,
11610        cx: &AppContext,
11611    ) {
11612        if cfg!(any(test, feature = "test-support")) {
11613            return;
11614        }
11615
11616        let Some(project) = &self.project else { return };
11617
11618        // If None, we are in a file without an extension
11619        let file = self
11620            .buffer
11621            .read(cx)
11622            .as_singleton()
11623            .and_then(|b| b.read(cx).file());
11624        let file_extension = file_extension.or(file
11625            .as_ref()
11626            .and_then(|file| Path::new(file.file_name(cx)).extension())
11627            .and_then(|e| e.to_str())
11628            .map(|a| a.to_string()));
11629
11630        let vim_mode = cx
11631            .global::<SettingsStore>()
11632            .raw_user_settings()
11633            .get("vim_mode")
11634            == Some(&serde_json::Value::Bool(true));
11635
11636        let copilot_enabled = all_language_settings(file, cx).inline_completions.provider
11637            == language::language_settings::InlineCompletionProvider::Copilot;
11638        let copilot_enabled_for_language = self
11639            .buffer
11640            .read(cx)
11641            .settings_at(0, cx)
11642            .show_inline_completions;
11643
11644        let telemetry = project.read(cx).client().telemetry().clone();
11645        telemetry.report_editor_event(
11646            file_extension,
11647            vim_mode,
11648            operation,
11649            copilot_enabled,
11650            copilot_enabled_for_language,
11651        )
11652    }
11653
11654    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
11655    /// with each line being an array of {text, highlight} objects.
11656    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
11657        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
11658            return;
11659        };
11660
11661        #[derive(Serialize)]
11662        struct Chunk<'a> {
11663            text: String,
11664            highlight: Option<&'a str>,
11665        }
11666
11667        let snapshot = buffer.read(cx).snapshot();
11668        let range = self
11669            .selected_text_range(cx)
11670            .and_then(|selected_range| {
11671                if selected_range.is_empty() {
11672                    None
11673                } else {
11674                    Some(selected_range)
11675                }
11676            })
11677            .unwrap_or_else(|| 0..snapshot.len());
11678
11679        let chunks = snapshot.chunks(range, true);
11680        let mut lines = Vec::new();
11681        let mut line: VecDeque<Chunk> = VecDeque::new();
11682
11683        let Some(style) = self.style.as_ref() else {
11684            return;
11685        };
11686
11687        for chunk in chunks {
11688            let highlight = chunk
11689                .syntax_highlight_id
11690                .and_then(|id| id.name(&style.syntax));
11691            let mut chunk_lines = chunk.text.split('\n').peekable();
11692            while let Some(text) = chunk_lines.next() {
11693                let mut merged_with_last_token = false;
11694                if let Some(last_token) = line.back_mut() {
11695                    if last_token.highlight == highlight {
11696                        last_token.text.push_str(text);
11697                        merged_with_last_token = true;
11698                    }
11699                }
11700
11701                if !merged_with_last_token {
11702                    line.push_back(Chunk {
11703                        text: text.into(),
11704                        highlight,
11705                    });
11706                }
11707
11708                if chunk_lines.peek().is_some() {
11709                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
11710                        line.pop_front();
11711                    }
11712                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
11713                        line.pop_back();
11714                    }
11715
11716                    lines.push(mem::take(&mut line));
11717                }
11718            }
11719        }
11720
11721        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
11722            return;
11723        };
11724        cx.write_to_clipboard(ClipboardItem::new_string(lines));
11725    }
11726
11727    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
11728        &self.inlay_hint_cache
11729    }
11730
11731    pub fn replay_insert_event(
11732        &mut self,
11733        text: &str,
11734        relative_utf16_range: Option<Range<isize>>,
11735        cx: &mut ViewContext<Self>,
11736    ) {
11737        if !self.input_enabled {
11738            cx.emit(EditorEvent::InputIgnored { text: text.into() });
11739            return;
11740        }
11741        if let Some(relative_utf16_range) = relative_utf16_range {
11742            let selections = self.selections.all::<OffsetUtf16>(cx);
11743            self.change_selections(None, cx, |s| {
11744                let new_ranges = selections.into_iter().map(|range| {
11745                    let start = OffsetUtf16(
11746                        range
11747                            .head()
11748                            .0
11749                            .saturating_add_signed(relative_utf16_range.start),
11750                    );
11751                    let end = OffsetUtf16(
11752                        range
11753                            .head()
11754                            .0
11755                            .saturating_add_signed(relative_utf16_range.end),
11756                    );
11757                    start..end
11758                });
11759                s.select_ranges(new_ranges);
11760            });
11761        }
11762
11763        self.handle_input(text, cx);
11764    }
11765
11766    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
11767        let Some(project) = self.project.as_ref() else {
11768            return false;
11769        };
11770        let project = project.read(cx);
11771
11772        let mut supports = false;
11773        self.buffer().read(cx).for_each_buffer(|buffer| {
11774            if !supports {
11775                supports = project
11776                    .language_servers_for_buffer(buffer.read(cx), cx)
11777                    .any(
11778                        |(_, server)| match server.capabilities().inlay_hint_provider {
11779                            Some(lsp::OneOf::Left(enabled)) => enabled,
11780                            Some(lsp::OneOf::Right(_)) => true,
11781                            None => false,
11782                        },
11783                    )
11784            }
11785        });
11786        supports
11787    }
11788
11789    pub fn focus(&self, cx: &mut WindowContext) {
11790        cx.focus(&self.focus_handle)
11791    }
11792
11793    pub fn is_focused(&self, cx: &WindowContext) -> bool {
11794        self.focus_handle.is_focused(cx)
11795    }
11796
11797    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
11798        cx.emit(EditorEvent::Focused);
11799
11800        if let Some(descendant) = self
11801            .last_focused_descendant
11802            .take()
11803            .and_then(|descendant| descendant.upgrade())
11804        {
11805            cx.focus(&descendant);
11806        } else {
11807            if let Some(blame) = self.blame.as_ref() {
11808                blame.update(cx, GitBlame::focus)
11809            }
11810
11811            self.blink_manager.update(cx, BlinkManager::enable);
11812            self.show_cursor_names(cx);
11813            self.buffer.update(cx, |buffer, cx| {
11814                buffer.finalize_last_transaction(cx);
11815                if self.leader_peer_id.is_none() {
11816                    buffer.set_active_selections(
11817                        &self.selections.disjoint_anchors(),
11818                        self.selections.line_mode,
11819                        self.cursor_shape,
11820                        cx,
11821                    );
11822                }
11823            });
11824        }
11825    }
11826
11827    fn handle_focus_in(&mut self, cx: &mut ViewContext<Self>) {
11828        cx.emit(EditorEvent::FocusedIn)
11829    }
11830
11831    fn handle_focus_out(&mut self, event: FocusOutEvent, _cx: &mut ViewContext<Self>) {
11832        if event.blurred != self.focus_handle {
11833            self.last_focused_descendant = Some(event.blurred);
11834        }
11835    }
11836
11837    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
11838        self.blink_manager.update(cx, BlinkManager::disable);
11839        self.buffer
11840            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
11841
11842        if let Some(blame) = self.blame.as_ref() {
11843            blame.update(cx, GitBlame::blur)
11844        }
11845        if !self.hover_state.focused(cx) {
11846            hide_hover(self, cx);
11847        }
11848
11849        self.hide_context_menu(cx);
11850        cx.emit(EditorEvent::Blurred);
11851        cx.notify();
11852    }
11853
11854    pub fn register_action<A: Action>(
11855        &mut self,
11856        listener: impl Fn(&A, &mut WindowContext) + 'static,
11857    ) -> Subscription {
11858        let id = self.next_editor_action_id.post_inc();
11859        let listener = Arc::new(listener);
11860        self.editor_actions.borrow_mut().insert(
11861            id,
11862            Box::new(move |cx| {
11863                let cx = cx.window_context();
11864                let listener = listener.clone();
11865                cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
11866                    let action = action.downcast_ref().unwrap();
11867                    if phase == DispatchPhase::Bubble {
11868                        listener(action, cx)
11869                    }
11870                })
11871            }),
11872        );
11873
11874        let editor_actions = self.editor_actions.clone();
11875        Subscription::new(move || {
11876            editor_actions.borrow_mut().remove(&id);
11877        })
11878    }
11879
11880    pub fn file_header_size(&self) -> u32 {
11881        self.file_header_size
11882    }
11883
11884    pub fn revert(
11885        &mut self,
11886        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11887        cx: &mut ViewContext<Self>,
11888    ) {
11889        self.buffer().update(cx, |multi_buffer, cx| {
11890            for (buffer_id, changes) in revert_changes {
11891                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11892                    buffer.update(cx, |buffer, cx| {
11893                        buffer.edit(
11894                            changes.into_iter().map(|(range, text)| {
11895                                (range, text.to_string().map(Arc::<str>::from))
11896                            }),
11897                            None,
11898                            cx,
11899                        );
11900                    });
11901                }
11902            }
11903        });
11904        self.change_selections(None, cx, |selections| selections.refresh());
11905    }
11906
11907    pub fn to_pixel_point(
11908        &mut self,
11909        source: multi_buffer::Anchor,
11910        editor_snapshot: &EditorSnapshot,
11911        cx: &mut ViewContext<Self>,
11912    ) -> Option<gpui::Point<Pixels>> {
11913        let source_point = source.to_display_point(editor_snapshot);
11914        self.display_to_pixel_point(source_point, editor_snapshot, cx)
11915    }
11916
11917    pub fn display_to_pixel_point(
11918        &mut self,
11919        source: DisplayPoint,
11920        editor_snapshot: &EditorSnapshot,
11921        cx: &mut ViewContext<Self>,
11922    ) -> Option<gpui::Point<Pixels>> {
11923        let line_height = self.style()?.text.line_height_in_pixels(cx.rem_size());
11924        let text_layout_details = self.text_layout_details(cx);
11925        let scroll_top = text_layout_details
11926            .scroll_anchor
11927            .scroll_position(editor_snapshot)
11928            .y;
11929
11930        if source.row().as_f32() < scroll_top.floor() {
11931            return None;
11932        }
11933        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
11934        let source_y = line_height * (source.row().as_f32() - scroll_top);
11935        Some(gpui::Point::new(source_x, source_y))
11936    }
11937
11938    fn gutter_bounds(&self) -> Option<Bounds<Pixels>> {
11939        let bounds = self.last_bounds?;
11940        Some(element::gutter_bounds(bounds, self.gutter_dimensions))
11941    }
11942
11943    pub fn has_active_completions_menu(&self) -> bool {
11944        self.context_menu.read().as_ref().map_or(false, |menu| {
11945            menu.visible() && matches!(menu, ContextMenu::Completions(_))
11946        })
11947    }
11948
11949    pub fn register_addon<T: Addon>(&mut self, instance: T) {
11950        self.addons
11951            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
11952    }
11953
11954    pub fn unregister_addon<T: Addon>(&mut self) {
11955        self.addons.remove(&std::any::TypeId::of::<T>());
11956    }
11957
11958    pub fn addon<T: Addon>(&self) -> Option<&T> {
11959        let type_id = std::any::TypeId::of::<T>();
11960        self.addons
11961            .get(&type_id)
11962            .and_then(|item| item.to_any().downcast_ref::<T>())
11963    }
11964}
11965
11966fn hunks_for_selections(
11967    multi_buffer_snapshot: &MultiBufferSnapshot,
11968    selections: &[Selection<Anchor>],
11969) -> Vec<DiffHunk<MultiBufferRow>> {
11970    let buffer_rows_for_selections = selections.iter().map(|selection| {
11971        let head = selection.head();
11972        let tail = selection.tail();
11973        let start = MultiBufferRow(tail.to_point(&multi_buffer_snapshot).row);
11974        let end = MultiBufferRow(head.to_point(&multi_buffer_snapshot).row);
11975        if start > end {
11976            end..start
11977        } else {
11978            start..end
11979        }
11980    });
11981
11982    hunks_for_rows(buffer_rows_for_selections, multi_buffer_snapshot)
11983}
11984
11985pub fn hunks_for_rows(
11986    rows: impl Iterator<Item = Range<MultiBufferRow>>,
11987    multi_buffer_snapshot: &MultiBufferSnapshot,
11988) -> Vec<DiffHunk<MultiBufferRow>> {
11989    let mut hunks = Vec::new();
11990    let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
11991        HashMap::default();
11992    for selected_multi_buffer_rows in rows {
11993        let query_rows =
11994            selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
11995        for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
11996            // Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
11997            // when the caret is just above or just below the deleted hunk.
11998            let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
11999            let related_to_selection = if allow_adjacent {
12000                hunk.associated_range.overlaps(&query_rows)
12001                    || hunk.associated_range.start == query_rows.end
12002                    || hunk.associated_range.end == query_rows.start
12003            } else {
12004                // `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
12005                // `hunk.associated_range` is exclusive (e.g. [2..3] means 2nd row is selected)
12006                hunk.associated_range.overlaps(&selected_multi_buffer_rows)
12007                    || selected_multi_buffer_rows.end == hunk.associated_range.start
12008            };
12009            if related_to_selection {
12010                if !processed_buffer_rows
12011                    .entry(hunk.buffer_id)
12012                    .or_default()
12013                    .insert(hunk.buffer_range.start..hunk.buffer_range.end)
12014                {
12015                    continue;
12016                }
12017                hunks.push(hunk);
12018            }
12019        }
12020    }
12021
12022    hunks
12023}
12024
12025pub trait CollaborationHub {
12026    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
12027    fn user_participant_indices<'a>(
12028        &self,
12029        cx: &'a AppContext,
12030    ) -> &'a HashMap<u64, ParticipantIndex>;
12031    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
12032}
12033
12034impl CollaborationHub for Model<Project> {
12035    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
12036        self.read(cx).collaborators()
12037    }
12038
12039    fn user_participant_indices<'a>(
12040        &self,
12041        cx: &'a AppContext,
12042    ) -> &'a HashMap<u64, ParticipantIndex> {
12043        self.read(cx).user_store().read(cx).participant_indices()
12044    }
12045
12046    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
12047        let this = self.read(cx);
12048        let user_ids = this.collaborators().values().map(|c| c.user_id);
12049        this.user_store().read_with(cx, |user_store, cx| {
12050            user_store.participant_names(user_ids, cx)
12051        })
12052    }
12053}
12054
12055pub trait CompletionProvider {
12056    fn completions(
12057        &self,
12058        buffer: &Model<Buffer>,
12059        buffer_position: text::Anchor,
12060        trigger: CompletionContext,
12061        cx: &mut ViewContext<Editor>,
12062    ) -> Task<Result<Vec<Completion>>>;
12063
12064    fn resolve_completions(
12065        &self,
12066        buffer: Model<Buffer>,
12067        completion_indices: Vec<usize>,
12068        completions: Arc<RwLock<Box<[Completion]>>>,
12069        cx: &mut ViewContext<Editor>,
12070    ) -> Task<Result<bool>>;
12071
12072    fn apply_additional_edits_for_completion(
12073        &self,
12074        buffer: Model<Buffer>,
12075        completion: Completion,
12076        push_to_history: bool,
12077        cx: &mut ViewContext<Editor>,
12078    ) -> Task<Result<Option<language::Transaction>>>;
12079
12080    fn is_completion_trigger(
12081        &self,
12082        buffer: &Model<Buffer>,
12083        position: language::Anchor,
12084        text: &str,
12085        trigger_in_words: bool,
12086        cx: &mut ViewContext<Editor>,
12087    ) -> bool;
12088
12089    fn sort_completions(&self) -> bool {
12090        true
12091    }
12092}
12093
12094fn snippet_completions(
12095    project: &Project,
12096    buffer: &Model<Buffer>,
12097    buffer_position: text::Anchor,
12098    cx: &mut AppContext,
12099) -> Vec<Completion> {
12100    let language = buffer.read(cx).language_at(buffer_position);
12101    let language_name = language.as_ref().map(|language| language.lsp_id());
12102    let snippet_store = project.snippets().read(cx);
12103    let snippets = snippet_store.snippets_for(language_name, cx);
12104
12105    if snippets.is_empty() {
12106        return vec![];
12107    }
12108    let snapshot = buffer.read(cx).text_snapshot();
12109    let chunks = snapshot.reversed_chunks_in_range(text::Anchor::MIN..buffer_position);
12110
12111    let mut lines = chunks.lines();
12112    let Some(line_at) = lines.next().filter(|line| !line.is_empty()) else {
12113        return vec![];
12114    };
12115
12116    let scope = language.map(|language| language.default_scope());
12117    let mut last_word = line_at
12118        .chars()
12119        .rev()
12120        .take_while(|c| char_kind(&scope, *c) == CharKind::Word)
12121        .collect::<String>();
12122    last_word = last_word.chars().rev().collect();
12123    let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
12124    let to_lsp = |point: &text::Anchor| {
12125        let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
12126        point_to_lsp(end)
12127    };
12128    let lsp_end = to_lsp(&buffer_position);
12129    snippets
12130        .into_iter()
12131        .filter_map(|snippet| {
12132            let matching_prefix = snippet
12133                .prefix
12134                .iter()
12135                .find(|prefix| prefix.starts_with(&last_word))?;
12136            let start = as_offset - last_word.len();
12137            let start = snapshot.anchor_before(start);
12138            let range = start..buffer_position;
12139            let lsp_start = to_lsp(&start);
12140            let lsp_range = lsp::Range {
12141                start: lsp_start,
12142                end: lsp_end,
12143            };
12144            Some(Completion {
12145                old_range: range,
12146                new_text: snippet.body.clone(),
12147                label: CodeLabel {
12148                    text: matching_prefix.clone(),
12149                    runs: vec![],
12150                    filter_range: 0..matching_prefix.len(),
12151                },
12152                server_id: LanguageServerId(usize::MAX),
12153                documentation: snippet
12154                    .description
12155                    .clone()
12156                    .map(|description| Documentation::SingleLine(description)),
12157                lsp_completion: lsp::CompletionItem {
12158                    label: snippet.prefix.first().unwrap().clone(),
12159                    kind: Some(CompletionItemKind::SNIPPET),
12160                    label_details: snippet.description.as_ref().map(|description| {
12161                        lsp::CompletionItemLabelDetails {
12162                            detail: Some(description.clone()),
12163                            description: None,
12164                        }
12165                    }),
12166                    insert_text_format: Some(InsertTextFormat::SNIPPET),
12167                    text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
12168                        lsp::InsertReplaceEdit {
12169                            new_text: snippet.body.clone(),
12170                            insert: lsp_range,
12171                            replace: lsp_range,
12172                        },
12173                    )),
12174                    filter_text: Some(snippet.body.clone()),
12175                    sort_text: Some(char::MAX.to_string()),
12176                    ..Default::default()
12177                },
12178                confirm: None,
12179            })
12180        })
12181        .collect()
12182}
12183
12184impl CompletionProvider for Model<Project> {
12185    fn completions(
12186        &self,
12187        buffer: &Model<Buffer>,
12188        buffer_position: text::Anchor,
12189        options: CompletionContext,
12190        cx: &mut ViewContext<Editor>,
12191    ) -> Task<Result<Vec<Completion>>> {
12192        self.update(cx, |project, cx| {
12193            let snippets = snippet_completions(project, buffer, buffer_position, cx);
12194            let project_completions = project.completions(&buffer, buffer_position, options, cx);
12195            cx.background_executor().spawn(async move {
12196                let mut completions = project_completions.await?;
12197                //let snippets = snippets.into_iter().;
12198                completions.extend(snippets);
12199                Ok(completions)
12200            })
12201        })
12202    }
12203
12204    fn resolve_completions(
12205        &self,
12206        buffer: Model<Buffer>,
12207        completion_indices: Vec<usize>,
12208        completions: Arc<RwLock<Box<[Completion]>>>,
12209        cx: &mut ViewContext<Editor>,
12210    ) -> Task<Result<bool>> {
12211        self.update(cx, |project, cx| {
12212            project.resolve_completions(buffer, completion_indices, completions, cx)
12213        })
12214    }
12215
12216    fn apply_additional_edits_for_completion(
12217        &self,
12218        buffer: Model<Buffer>,
12219        completion: Completion,
12220        push_to_history: bool,
12221        cx: &mut ViewContext<Editor>,
12222    ) -> Task<Result<Option<language::Transaction>>> {
12223        self.update(cx, |project, cx| {
12224            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
12225        })
12226    }
12227
12228    fn is_completion_trigger(
12229        &self,
12230        buffer: &Model<Buffer>,
12231        position: language::Anchor,
12232        text: &str,
12233        trigger_in_words: bool,
12234        cx: &mut ViewContext<Editor>,
12235    ) -> bool {
12236        if !EditorSettings::get_global(cx).show_completions_on_input {
12237            return false;
12238        }
12239
12240        let mut chars = text.chars();
12241        let char = if let Some(char) = chars.next() {
12242            char
12243        } else {
12244            return false;
12245        };
12246        if chars.next().is_some() {
12247            return false;
12248        }
12249
12250        let buffer = buffer.read(cx);
12251        let scope = buffer.snapshot().language_scope_at(position);
12252        if trigger_in_words && char_kind(&scope, char) == CharKind::Word {
12253            return true;
12254        }
12255
12256        buffer
12257            .completion_triggers()
12258            .iter()
12259            .any(|string| string == text)
12260    }
12261}
12262
12263fn inlay_hint_settings(
12264    location: Anchor,
12265    snapshot: &MultiBufferSnapshot,
12266    cx: &mut ViewContext<'_, Editor>,
12267) -> InlayHintSettings {
12268    let file = snapshot.file_at(location);
12269    let language = snapshot.language_at(location);
12270    let settings = all_language_settings(file, cx);
12271    settings
12272        .language(language.map(|l| l.name()).as_deref())
12273        .inlay_hints
12274}
12275
12276fn consume_contiguous_rows(
12277    contiguous_row_selections: &mut Vec<Selection<Point>>,
12278    selection: &Selection<Point>,
12279    display_map: &DisplaySnapshot,
12280    selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
12281) -> (MultiBufferRow, MultiBufferRow) {
12282    contiguous_row_selections.push(selection.clone());
12283    let start_row = MultiBufferRow(selection.start.row);
12284    let mut end_row = ending_row(selection, display_map);
12285
12286    while let Some(next_selection) = selections.peek() {
12287        if next_selection.start.row <= end_row.0 {
12288            end_row = ending_row(next_selection, display_map);
12289            contiguous_row_selections.push(selections.next().unwrap().clone());
12290        } else {
12291            break;
12292        }
12293    }
12294    (start_row, end_row)
12295}
12296
12297fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
12298    if next_selection.end.column > 0 || next_selection.is_empty() {
12299        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
12300    } else {
12301        MultiBufferRow(next_selection.end.row)
12302    }
12303}
12304
12305impl EditorSnapshot {
12306    pub fn remote_selections_in_range<'a>(
12307        &'a self,
12308        range: &'a Range<Anchor>,
12309        collaboration_hub: &dyn CollaborationHub,
12310        cx: &'a AppContext,
12311    ) -> impl 'a + Iterator<Item = RemoteSelection> {
12312        let participant_names = collaboration_hub.user_names(cx);
12313        let participant_indices = collaboration_hub.user_participant_indices(cx);
12314        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
12315        let collaborators_by_replica_id = collaborators_by_peer_id
12316            .iter()
12317            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
12318            .collect::<HashMap<_, _>>();
12319        self.buffer_snapshot
12320            .selections_in_range(range, false)
12321            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
12322                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
12323                let participant_index = participant_indices.get(&collaborator.user_id).copied();
12324                let user_name = participant_names.get(&collaborator.user_id).cloned();
12325                Some(RemoteSelection {
12326                    replica_id,
12327                    selection,
12328                    cursor_shape,
12329                    line_mode,
12330                    participant_index,
12331                    peer_id: collaborator.peer_id,
12332                    user_name,
12333                })
12334            })
12335    }
12336
12337    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
12338        self.display_snapshot.buffer_snapshot.language_at(position)
12339    }
12340
12341    pub fn is_focused(&self) -> bool {
12342        self.is_focused
12343    }
12344
12345    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
12346        self.placeholder_text.as_ref()
12347    }
12348
12349    pub fn scroll_position(&self) -> gpui::Point<f32> {
12350        self.scroll_anchor.scroll_position(&self.display_snapshot)
12351    }
12352
12353    fn gutter_dimensions(
12354        &self,
12355        font_id: FontId,
12356        font_size: Pixels,
12357        em_width: Pixels,
12358        max_line_number_width: Pixels,
12359        cx: &AppContext,
12360    ) -> GutterDimensions {
12361        if !self.show_gutter {
12362            return GutterDimensions::default();
12363        }
12364        let descent = cx.text_system().descent(font_id, font_size);
12365
12366        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
12367            matches!(
12368                ProjectSettings::get_global(cx).git.git_gutter,
12369                Some(GitGutterSetting::TrackedFiles)
12370            )
12371        });
12372        let gutter_settings = EditorSettings::get_global(cx).gutter;
12373        let show_line_numbers = self
12374            .show_line_numbers
12375            .unwrap_or(gutter_settings.line_numbers);
12376        let line_gutter_width = if show_line_numbers {
12377            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
12378            let min_width_for_number_on_gutter = em_width * 4.0;
12379            max_line_number_width.max(min_width_for_number_on_gutter)
12380        } else {
12381            0.0.into()
12382        };
12383
12384        let show_code_actions = self
12385            .show_code_actions
12386            .unwrap_or(gutter_settings.code_actions);
12387
12388        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
12389
12390        let git_blame_entries_width = self
12391            .render_git_blame_gutter
12392            .then_some(em_width * GIT_BLAME_GUTTER_WIDTH_CHARS);
12393
12394        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
12395        left_padding += if show_code_actions || show_runnables {
12396            em_width * 3.0
12397        } else if show_git_gutter && show_line_numbers {
12398            em_width * 2.0
12399        } else if show_git_gutter || show_line_numbers {
12400            em_width
12401        } else {
12402            px(0.)
12403        };
12404
12405        let right_padding = if gutter_settings.folds && show_line_numbers {
12406            em_width * 4.0
12407        } else if gutter_settings.folds {
12408            em_width * 3.0
12409        } else if show_line_numbers {
12410            em_width
12411        } else {
12412            px(0.)
12413        };
12414
12415        GutterDimensions {
12416            left_padding,
12417            right_padding,
12418            width: line_gutter_width + left_padding + right_padding,
12419            margin: -descent,
12420            git_blame_entries_width,
12421        }
12422    }
12423
12424    pub fn render_fold_toggle(
12425        &self,
12426        buffer_row: MultiBufferRow,
12427        row_contains_cursor: bool,
12428        editor: View<Editor>,
12429        cx: &mut WindowContext,
12430    ) -> Option<AnyElement> {
12431        let folded = self.is_line_folded(buffer_row);
12432
12433        if let Some(crease) = self
12434            .crease_snapshot
12435            .query_row(buffer_row, &self.buffer_snapshot)
12436        {
12437            let toggle_callback = Arc::new(move |folded, cx: &mut WindowContext| {
12438                if folded {
12439                    editor.update(cx, |editor, cx| {
12440                        editor.fold_at(&crate::FoldAt { buffer_row }, cx)
12441                    });
12442                } else {
12443                    editor.update(cx, |editor, cx| {
12444                        editor.unfold_at(&crate::UnfoldAt { buffer_row }, cx)
12445                    });
12446                }
12447            });
12448
12449            Some((crease.render_toggle)(
12450                buffer_row,
12451                folded,
12452                toggle_callback,
12453                cx,
12454            ))
12455        } else if folded
12456            || (self.starts_indent(buffer_row) && (row_contains_cursor || self.gutter_hovered))
12457        {
12458            Some(
12459                Disclosure::new(("indent-fold-indicator", buffer_row.0), !folded)
12460                    .selected(folded)
12461                    .on_click(cx.listener_for(&editor, move |this, _e, cx| {
12462                        if folded {
12463                            this.unfold_at(&UnfoldAt { buffer_row }, cx);
12464                        } else {
12465                            this.fold_at(&FoldAt { buffer_row }, cx);
12466                        }
12467                    }))
12468                    .into_any_element(),
12469            )
12470        } else {
12471            None
12472        }
12473    }
12474
12475    pub fn render_crease_trailer(
12476        &self,
12477        buffer_row: MultiBufferRow,
12478        cx: &mut WindowContext,
12479    ) -> Option<AnyElement> {
12480        let folded = self.is_line_folded(buffer_row);
12481        let crease = self
12482            .crease_snapshot
12483            .query_row(buffer_row, &self.buffer_snapshot)?;
12484        Some((crease.render_trailer)(buffer_row, folded, cx))
12485    }
12486}
12487
12488impl Deref for EditorSnapshot {
12489    type Target = DisplaySnapshot;
12490
12491    fn deref(&self) -> &Self::Target {
12492        &self.display_snapshot
12493    }
12494}
12495
12496#[derive(Clone, Debug, PartialEq, Eq)]
12497pub enum EditorEvent {
12498    InputIgnored {
12499        text: Arc<str>,
12500    },
12501    InputHandled {
12502        utf16_range_to_replace: Option<Range<isize>>,
12503        text: Arc<str>,
12504    },
12505    ExcerptsAdded {
12506        buffer: Model<Buffer>,
12507        predecessor: ExcerptId,
12508        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
12509    },
12510    ExcerptsRemoved {
12511        ids: Vec<ExcerptId>,
12512    },
12513    ExcerptsEdited {
12514        ids: Vec<ExcerptId>,
12515    },
12516    ExcerptsExpanded {
12517        ids: Vec<ExcerptId>,
12518    },
12519    BufferEdited,
12520    Edited {
12521        transaction_id: clock::Lamport,
12522    },
12523    Reparsed(BufferId),
12524    Focused,
12525    FocusedIn,
12526    Blurred,
12527    DirtyChanged,
12528    Saved,
12529    TitleChanged,
12530    DiffBaseChanged,
12531    SelectionsChanged {
12532        local: bool,
12533    },
12534    ScrollPositionChanged {
12535        local: bool,
12536        autoscroll: bool,
12537    },
12538    Closed,
12539    TransactionUndone {
12540        transaction_id: clock::Lamport,
12541    },
12542    TransactionBegun {
12543        transaction_id: clock::Lamport,
12544    },
12545}
12546
12547impl EventEmitter<EditorEvent> for Editor {}
12548
12549impl FocusableView for Editor {
12550    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
12551        self.focus_handle.clone()
12552    }
12553}
12554
12555impl Render for Editor {
12556    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
12557        let settings = ThemeSettings::get_global(cx);
12558
12559        let text_style = match self.mode {
12560            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
12561                color: cx.theme().colors().editor_foreground,
12562                font_family: settings.ui_font.family.clone(),
12563                font_features: settings.ui_font.features.clone(),
12564                font_fallbacks: settings.ui_font.fallbacks.clone(),
12565                font_size: rems(0.875).into(),
12566                font_weight: settings.ui_font.weight,
12567                line_height: relative(settings.buffer_line_height.value()),
12568                ..Default::default()
12569            },
12570            EditorMode::Full => TextStyle {
12571                color: cx.theme().colors().editor_foreground,
12572                font_family: settings.buffer_font.family.clone(),
12573                font_features: settings.buffer_font.features.clone(),
12574                font_fallbacks: settings.buffer_font.fallbacks.clone(),
12575                font_size: settings.buffer_font_size(cx).into(),
12576                font_weight: settings.buffer_font.weight,
12577                line_height: relative(settings.buffer_line_height.value()),
12578                ..Default::default()
12579            },
12580        };
12581
12582        let background = match self.mode {
12583            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
12584            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
12585            EditorMode::Full => cx.theme().colors().editor_background,
12586        };
12587
12588        EditorElement::new(
12589            cx.view(),
12590            EditorStyle {
12591                background,
12592                local_player: cx.theme().players().local(),
12593                text: text_style,
12594                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
12595                syntax: cx.theme().syntax().clone(),
12596                status: cx.theme().status().clone(),
12597                inlay_hints_style: HighlightStyle {
12598                    color: Some(cx.theme().status().hint),
12599                    ..HighlightStyle::default()
12600                },
12601                suggestions_style: HighlightStyle {
12602                    color: Some(cx.theme().status().predictive),
12603                    ..HighlightStyle::default()
12604                },
12605                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
12606            },
12607        )
12608    }
12609}
12610
12611impl ViewInputHandler for Editor {
12612    fn text_for_range(
12613        &mut self,
12614        range_utf16: Range<usize>,
12615        cx: &mut ViewContext<Self>,
12616    ) -> Option<String> {
12617        Some(
12618            self.buffer
12619                .read(cx)
12620                .read(cx)
12621                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
12622                .collect(),
12623        )
12624    }
12625
12626    fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
12627        // Prevent the IME menu from appearing when holding down an alphabetic key
12628        // while input is disabled.
12629        if !self.input_enabled {
12630            return None;
12631        }
12632
12633        let range = self.selections.newest::<OffsetUtf16>(cx).range();
12634        Some(range.start.0..range.end.0)
12635    }
12636
12637    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
12638        let snapshot = self.buffer.read(cx).read(cx);
12639        let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
12640        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
12641    }
12642
12643    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
12644        self.clear_highlights::<InputComposition>(cx);
12645        self.ime_transaction.take();
12646    }
12647
12648    fn replace_text_in_range(
12649        &mut self,
12650        range_utf16: Option<Range<usize>>,
12651        text: &str,
12652        cx: &mut ViewContext<Self>,
12653    ) {
12654        if !self.input_enabled {
12655            cx.emit(EditorEvent::InputIgnored { text: text.into() });
12656            return;
12657        }
12658
12659        self.transact(cx, |this, cx| {
12660            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
12661                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
12662                Some(this.selection_replacement_ranges(range_utf16, cx))
12663            } else {
12664                this.marked_text_ranges(cx)
12665            };
12666
12667            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
12668                let newest_selection_id = this.selections.newest_anchor().id;
12669                this.selections
12670                    .all::<OffsetUtf16>(cx)
12671                    .iter()
12672                    .zip(ranges_to_replace.iter())
12673                    .find_map(|(selection, range)| {
12674                        if selection.id == newest_selection_id {
12675                            Some(
12676                                (range.start.0 as isize - selection.head().0 as isize)
12677                                    ..(range.end.0 as isize - selection.head().0 as isize),
12678                            )
12679                        } else {
12680                            None
12681                        }
12682                    })
12683            });
12684
12685            cx.emit(EditorEvent::InputHandled {
12686                utf16_range_to_replace: range_to_replace,
12687                text: text.into(),
12688            });
12689
12690            if let Some(new_selected_ranges) = new_selected_ranges {
12691                this.change_selections(None, cx, |selections| {
12692                    selections.select_ranges(new_selected_ranges)
12693                });
12694                this.backspace(&Default::default(), cx);
12695            }
12696
12697            this.handle_input(text, cx);
12698        });
12699
12700        if let Some(transaction) = self.ime_transaction {
12701            self.buffer.update(cx, |buffer, cx| {
12702                buffer.group_until_transaction(transaction, cx);
12703            });
12704        }
12705
12706        self.unmark_text(cx);
12707    }
12708
12709    fn replace_and_mark_text_in_range(
12710        &mut self,
12711        range_utf16: Option<Range<usize>>,
12712        text: &str,
12713        new_selected_range_utf16: Option<Range<usize>>,
12714        cx: &mut ViewContext<Self>,
12715    ) {
12716        if !self.input_enabled {
12717            return;
12718        }
12719
12720        let transaction = self.transact(cx, |this, cx| {
12721            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
12722                let snapshot = this.buffer.read(cx).read(cx);
12723                if let Some(relative_range_utf16) = range_utf16.as_ref() {
12724                    for marked_range in &mut marked_ranges {
12725                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
12726                        marked_range.start.0 += relative_range_utf16.start;
12727                        marked_range.start =
12728                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
12729                        marked_range.end =
12730                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
12731                    }
12732                }
12733                Some(marked_ranges)
12734            } else if let Some(range_utf16) = range_utf16 {
12735                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
12736                Some(this.selection_replacement_ranges(range_utf16, cx))
12737            } else {
12738                None
12739            };
12740
12741            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
12742                let newest_selection_id = this.selections.newest_anchor().id;
12743                this.selections
12744                    .all::<OffsetUtf16>(cx)
12745                    .iter()
12746                    .zip(ranges_to_replace.iter())
12747                    .find_map(|(selection, range)| {
12748                        if selection.id == newest_selection_id {
12749                            Some(
12750                                (range.start.0 as isize - selection.head().0 as isize)
12751                                    ..(range.end.0 as isize - selection.head().0 as isize),
12752                            )
12753                        } else {
12754                            None
12755                        }
12756                    })
12757            });
12758
12759            cx.emit(EditorEvent::InputHandled {
12760                utf16_range_to_replace: range_to_replace,
12761                text: text.into(),
12762            });
12763
12764            if let Some(ranges) = ranges_to_replace {
12765                this.change_selections(None, cx, |s| s.select_ranges(ranges));
12766            }
12767
12768            let marked_ranges = {
12769                let snapshot = this.buffer.read(cx).read(cx);
12770                this.selections
12771                    .disjoint_anchors()
12772                    .iter()
12773                    .map(|selection| {
12774                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
12775                    })
12776                    .collect::<Vec<_>>()
12777            };
12778
12779            if text.is_empty() {
12780                this.unmark_text(cx);
12781            } else {
12782                this.highlight_text::<InputComposition>(
12783                    marked_ranges.clone(),
12784                    HighlightStyle {
12785                        underline: Some(UnderlineStyle {
12786                            thickness: px(1.),
12787                            color: None,
12788                            wavy: false,
12789                        }),
12790                        ..Default::default()
12791                    },
12792                    cx,
12793                );
12794            }
12795
12796            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
12797            let use_autoclose = this.use_autoclose;
12798            let use_auto_surround = this.use_auto_surround;
12799            this.set_use_autoclose(false);
12800            this.set_use_auto_surround(false);
12801            this.handle_input(text, cx);
12802            this.set_use_autoclose(use_autoclose);
12803            this.set_use_auto_surround(use_auto_surround);
12804
12805            if let Some(new_selected_range) = new_selected_range_utf16 {
12806                let snapshot = this.buffer.read(cx).read(cx);
12807                let new_selected_ranges = marked_ranges
12808                    .into_iter()
12809                    .map(|marked_range| {
12810                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
12811                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
12812                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
12813                        snapshot.clip_offset_utf16(new_start, Bias::Left)
12814                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
12815                    })
12816                    .collect::<Vec<_>>();
12817
12818                drop(snapshot);
12819                this.change_selections(None, cx, |selections| {
12820                    selections.select_ranges(new_selected_ranges)
12821                });
12822            }
12823        });
12824
12825        self.ime_transaction = self.ime_transaction.or(transaction);
12826        if let Some(transaction) = self.ime_transaction {
12827            self.buffer.update(cx, |buffer, cx| {
12828                buffer.group_until_transaction(transaction, cx);
12829            });
12830        }
12831
12832        if self.text_highlights::<InputComposition>(cx).is_none() {
12833            self.ime_transaction.take();
12834        }
12835    }
12836
12837    fn bounds_for_range(
12838        &mut self,
12839        range_utf16: Range<usize>,
12840        element_bounds: gpui::Bounds<Pixels>,
12841        cx: &mut ViewContext<Self>,
12842    ) -> Option<gpui::Bounds<Pixels>> {
12843        let text_layout_details = self.text_layout_details(cx);
12844        let style = &text_layout_details.editor_style;
12845        let font_id = cx.text_system().resolve_font(&style.text.font());
12846        let font_size = style.text.font_size.to_pixels(cx.rem_size());
12847        let line_height = style.text.line_height_in_pixels(cx.rem_size());
12848
12849        let em_width = cx
12850            .text_system()
12851            .typographic_bounds(font_id, font_size, 'm')
12852            .unwrap()
12853            .size
12854            .width;
12855
12856        let snapshot = self.snapshot(cx);
12857        let scroll_position = snapshot.scroll_position();
12858        let scroll_left = scroll_position.x * em_width;
12859
12860        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
12861        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
12862            + self.gutter_dimensions.width;
12863        let y = line_height * (start.row().as_f32() - scroll_position.y);
12864
12865        Some(Bounds {
12866            origin: element_bounds.origin + point(x, y),
12867            size: size(em_width, line_height),
12868        })
12869    }
12870}
12871
12872trait SelectionExt {
12873    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
12874    fn spanned_rows(
12875        &self,
12876        include_end_if_at_line_start: bool,
12877        map: &DisplaySnapshot,
12878    ) -> Range<MultiBufferRow>;
12879}
12880
12881impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
12882    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
12883        let start = self
12884            .start
12885            .to_point(&map.buffer_snapshot)
12886            .to_display_point(map);
12887        let end = self
12888            .end
12889            .to_point(&map.buffer_snapshot)
12890            .to_display_point(map);
12891        if self.reversed {
12892            end..start
12893        } else {
12894            start..end
12895        }
12896    }
12897
12898    fn spanned_rows(
12899        &self,
12900        include_end_if_at_line_start: bool,
12901        map: &DisplaySnapshot,
12902    ) -> Range<MultiBufferRow> {
12903        let start = self.start.to_point(&map.buffer_snapshot);
12904        let mut end = self.end.to_point(&map.buffer_snapshot);
12905        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
12906            end.row -= 1;
12907        }
12908
12909        let buffer_start = map.prev_line_boundary(start).0;
12910        let buffer_end = map.next_line_boundary(end).0;
12911        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
12912    }
12913}
12914
12915impl<T: InvalidationRegion> InvalidationStack<T> {
12916    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
12917    where
12918        S: Clone + ToOffset,
12919    {
12920        while let Some(region) = self.last() {
12921            let all_selections_inside_invalidation_ranges =
12922                if selections.len() == region.ranges().len() {
12923                    selections
12924                        .iter()
12925                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
12926                        .all(|(selection, invalidation_range)| {
12927                            let head = selection.head().to_offset(buffer);
12928                            invalidation_range.start <= head && invalidation_range.end >= head
12929                        })
12930                } else {
12931                    false
12932                };
12933
12934            if all_selections_inside_invalidation_ranges {
12935                break;
12936            } else {
12937                self.pop();
12938            }
12939        }
12940    }
12941}
12942
12943impl<T> Default for InvalidationStack<T> {
12944    fn default() -> Self {
12945        Self(Default::default())
12946    }
12947}
12948
12949impl<T> Deref for InvalidationStack<T> {
12950    type Target = Vec<T>;
12951
12952    fn deref(&self) -> &Self::Target {
12953        &self.0
12954    }
12955}
12956
12957impl<T> DerefMut for InvalidationStack<T> {
12958    fn deref_mut(&mut self) -> &mut Self::Target {
12959        &mut self.0
12960    }
12961}
12962
12963impl InvalidationRegion for SnippetState {
12964    fn ranges(&self) -> &[Range<Anchor>] {
12965        &self.ranges[self.active_index]
12966    }
12967}
12968
12969pub fn diagnostic_block_renderer(
12970    diagnostic: Diagnostic,
12971    max_message_rows: Option<u8>,
12972    allow_closing: bool,
12973    _is_valid: bool,
12974) -> RenderBlock {
12975    let (text_without_backticks, code_ranges) =
12976        highlight_diagnostic_message(&diagnostic, max_message_rows);
12977
12978    Box::new(move |cx: &mut BlockContext| {
12979        let group_id: SharedString = cx.block_id.to_string().into();
12980
12981        let mut text_style = cx.text_style().clone();
12982        text_style.color = diagnostic_style(diagnostic.severity, cx.theme().status());
12983        let theme_settings = ThemeSettings::get_global(cx);
12984        text_style.font_family = theme_settings.buffer_font.family.clone();
12985        text_style.font_style = theme_settings.buffer_font.style;
12986        text_style.font_features = theme_settings.buffer_font.features.clone();
12987        text_style.font_weight = theme_settings.buffer_font.weight;
12988
12989        let multi_line_diagnostic = diagnostic.message.contains('\n');
12990
12991        let buttons = |diagnostic: &Diagnostic, block_id: BlockId| {
12992            if multi_line_diagnostic {
12993                v_flex()
12994            } else {
12995                h_flex()
12996            }
12997            .when(allow_closing, |div| {
12998                div.children(diagnostic.is_primary.then(|| {
12999                    IconButton::new(("close-block", EntityId::from(block_id)), IconName::XCircle)
13000                        .icon_color(Color::Muted)
13001                        .size(ButtonSize::Compact)
13002                        .style(ButtonStyle::Transparent)
13003                        .visible_on_hover(group_id.clone())
13004                        .on_click(move |_click, cx| cx.dispatch_action(Box::new(Cancel)))
13005                        .tooltip(|cx| Tooltip::for_action("Close Diagnostics", &Cancel, cx))
13006                }))
13007            })
13008            .child(
13009                IconButton::new(("copy-block", EntityId::from(block_id)), IconName::Copy)
13010                    .icon_color(Color::Muted)
13011                    .size(ButtonSize::Compact)
13012                    .style(ButtonStyle::Transparent)
13013                    .visible_on_hover(group_id.clone())
13014                    .on_click({
13015                        let message = diagnostic.message.clone();
13016                        move |_click, cx| {
13017                            cx.write_to_clipboard(ClipboardItem::new_string(message.clone()))
13018                        }
13019                    })
13020                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
13021            )
13022        };
13023
13024        let icon_size = buttons(&diagnostic, cx.block_id)
13025            .into_any_element()
13026            .layout_as_root(AvailableSpace::min_size(), cx);
13027
13028        h_flex()
13029            .id(cx.block_id)
13030            .group(group_id.clone())
13031            .relative()
13032            .size_full()
13033            .pl(cx.gutter_dimensions.width)
13034            .w(cx.max_width + cx.gutter_dimensions.width)
13035            .child(
13036                div()
13037                    .flex()
13038                    .w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
13039                    .flex_shrink(),
13040            )
13041            .child(buttons(&diagnostic, cx.block_id))
13042            .child(div().flex().flex_shrink_0().child(
13043                StyledText::new(text_without_backticks.clone()).with_highlights(
13044                    &text_style,
13045                    code_ranges.iter().map(|range| {
13046                        (
13047                            range.clone(),
13048                            HighlightStyle {
13049                                font_weight: Some(FontWeight::BOLD),
13050                                ..Default::default()
13051                            },
13052                        )
13053                    }),
13054                ),
13055            ))
13056            .into_any_element()
13057    })
13058}
13059
13060pub fn highlight_diagnostic_message(
13061    diagnostic: &Diagnostic,
13062    mut max_message_rows: Option<u8>,
13063) -> (SharedString, Vec<Range<usize>>) {
13064    let mut text_without_backticks = String::new();
13065    let mut code_ranges = Vec::new();
13066
13067    if let Some(source) = &diagnostic.source {
13068        text_without_backticks.push_str(&source);
13069        code_ranges.push(0..source.len());
13070        text_without_backticks.push_str(": ");
13071    }
13072
13073    let mut prev_offset = 0;
13074    let mut in_code_block = false;
13075    let has_row_limit = max_message_rows.is_some();
13076    let mut newline_indices = diagnostic
13077        .message
13078        .match_indices('\n')
13079        .filter(|_| has_row_limit)
13080        .map(|(ix, _)| ix)
13081        .fuse()
13082        .peekable();
13083
13084    for (quote_ix, _) in diagnostic
13085        .message
13086        .match_indices('`')
13087        .chain([(diagnostic.message.len(), "")])
13088    {
13089        let mut first_newline_ix = None;
13090        let mut last_newline_ix = None;
13091        while let Some(newline_ix) = newline_indices.peek() {
13092            if *newline_ix < quote_ix {
13093                if first_newline_ix.is_none() {
13094                    first_newline_ix = Some(*newline_ix);
13095                }
13096                last_newline_ix = Some(*newline_ix);
13097
13098                if let Some(rows_left) = &mut max_message_rows {
13099                    if *rows_left == 0 {
13100                        break;
13101                    } else {
13102                        *rows_left -= 1;
13103                    }
13104                }
13105                let _ = newline_indices.next();
13106            } else {
13107                break;
13108            }
13109        }
13110        let prev_len = text_without_backticks.len();
13111        let new_text = &diagnostic.message[prev_offset..first_newline_ix.unwrap_or(quote_ix)];
13112        text_without_backticks.push_str(new_text);
13113        if in_code_block {
13114            code_ranges.push(prev_len..text_without_backticks.len());
13115        }
13116        prev_offset = last_newline_ix.unwrap_or(quote_ix) + 1;
13117        in_code_block = !in_code_block;
13118        if first_newline_ix.map_or(false, |newline_ix| newline_ix < quote_ix) {
13119            text_without_backticks.push_str("...");
13120            break;
13121        }
13122    }
13123
13124    (text_without_backticks.into(), code_ranges)
13125}
13126
13127fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
13128    match severity {
13129        DiagnosticSeverity::ERROR => colors.error,
13130        DiagnosticSeverity::WARNING => colors.warning,
13131        DiagnosticSeverity::INFORMATION => colors.info,
13132        DiagnosticSeverity::HINT => colors.info,
13133        _ => colors.ignored,
13134    }
13135}
13136
13137pub fn styled_runs_for_code_label<'a>(
13138    label: &'a CodeLabel,
13139    syntax_theme: &'a theme::SyntaxTheme,
13140) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
13141    let fade_out = HighlightStyle {
13142        fade_out: Some(0.35),
13143        ..Default::default()
13144    };
13145
13146    let mut prev_end = label.filter_range.end;
13147    label
13148        .runs
13149        .iter()
13150        .enumerate()
13151        .flat_map(move |(ix, (range, highlight_id))| {
13152            let style = if let Some(style) = highlight_id.style(syntax_theme) {
13153                style
13154            } else {
13155                return Default::default();
13156            };
13157            let mut muted_style = style;
13158            muted_style.highlight(fade_out);
13159
13160            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
13161            if range.start >= label.filter_range.end {
13162                if range.start > prev_end {
13163                    runs.push((prev_end..range.start, fade_out));
13164                }
13165                runs.push((range.clone(), muted_style));
13166            } else if range.end <= label.filter_range.end {
13167                runs.push((range.clone(), style));
13168            } else {
13169                runs.push((range.start..label.filter_range.end, style));
13170                runs.push((label.filter_range.end..range.end, muted_style));
13171            }
13172            prev_end = cmp::max(prev_end, range.end);
13173
13174            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
13175                runs.push((prev_end..label.text.len(), fade_out));
13176            }
13177
13178            runs
13179        })
13180}
13181
13182pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
13183    let mut prev_index = 0;
13184    let mut prev_codepoint: Option<char> = None;
13185    text.char_indices()
13186        .chain([(text.len(), '\0')])
13187        .filter_map(move |(index, codepoint)| {
13188            let prev_codepoint = prev_codepoint.replace(codepoint)?;
13189            let is_boundary = index == text.len()
13190                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
13191                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
13192            if is_boundary {
13193                let chunk = &text[prev_index..index];
13194                prev_index = index;
13195                Some(chunk)
13196            } else {
13197                None
13198            }
13199        })
13200}
13201
13202pub trait RangeToAnchorExt: Sized {
13203    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
13204
13205    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
13206        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
13207        anchor_range.start.to_display_point(&snapshot)..anchor_range.end.to_display_point(&snapshot)
13208    }
13209}
13210
13211impl<T: ToOffset> RangeToAnchorExt for Range<T> {
13212    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
13213        let start_offset = self.start.to_offset(snapshot);
13214        let end_offset = self.end.to_offset(snapshot);
13215        if start_offset == end_offset {
13216            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
13217        } else {
13218            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
13219        }
13220    }
13221}
13222
13223pub trait RowExt {
13224    fn as_f32(&self) -> f32;
13225
13226    fn next_row(&self) -> Self;
13227
13228    fn previous_row(&self) -> Self;
13229
13230    fn minus(&self, other: Self) -> u32;
13231}
13232
13233impl RowExt for DisplayRow {
13234    fn as_f32(&self) -> f32 {
13235        self.0 as f32
13236    }
13237
13238    fn next_row(&self) -> Self {
13239        Self(self.0 + 1)
13240    }
13241
13242    fn previous_row(&self) -> Self {
13243        Self(self.0.saturating_sub(1))
13244    }
13245
13246    fn minus(&self, other: Self) -> u32 {
13247        self.0 - other.0
13248    }
13249}
13250
13251impl RowExt for MultiBufferRow {
13252    fn as_f32(&self) -> f32 {
13253        self.0 as f32
13254    }
13255
13256    fn next_row(&self) -> Self {
13257        Self(self.0 + 1)
13258    }
13259
13260    fn previous_row(&self) -> Self {
13261        Self(self.0.saturating_sub(1))
13262    }
13263
13264    fn minus(&self, other: Self) -> u32 {
13265        self.0 - other.0
13266    }
13267}
13268
13269trait RowRangeExt {
13270    type Row;
13271
13272    fn len(&self) -> usize;
13273
13274    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
13275}
13276
13277impl RowRangeExt for Range<MultiBufferRow> {
13278    type Row = MultiBufferRow;
13279
13280    fn len(&self) -> usize {
13281        (self.end.0 - self.start.0) as usize
13282    }
13283
13284    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
13285        (self.start.0..self.end.0).map(MultiBufferRow)
13286    }
13287}
13288
13289impl RowRangeExt for Range<DisplayRow> {
13290    type Row = DisplayRow;
13291
13292    fn len(&self) -> usize {
13293        (self.end.0 - self.start.0) as usize
13294    }
13295
13296    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
13297        (self.start.0..self.end.0).map(DisplayRow)
13298    }
13299}
13300
13301fn hunk_status(hunk: &DiffHunk<MultiBufferRow>) -> DiffHunkStatus {
13302    if hunk.diff_base_byte_range.is_empty() {
13303        DiffHunkStatus::Added
13304    } else if hunk.associated_range.is_empty() {
13305        DiffHunkStatus::Removed
13306    } else {
13307        DiffHunkStatus::Modified
13308    }
13309}
13310
13311/// If select range has more than one line, we
13312/// just point the cursor to range.start.
13313fn check_multiline_range(buffer: &Buffer, range: Range<usize>) -> Range<usize> {
13314    if buffer.offset_to_point(range.start).row == buffer.offset_to_point(range.end).row {
13315        range
13316    } else {
13317        range.start..range.start
13318    }
13319}