1#![allow(unused)]
2mod blink_manager;
3pub mod display_map;
4mod editor_settings;
5mod element;
6mod inlay_hint_cache;
7
8mod git;
9mod highlight_matching_bracket;
10mod hover_popover;
11pub mod items;
12mod link_go_to_definition;
13mod mouse_context_menu;
14pub mod movement;
15mod persistence;
16pub mod scroll;
17pub mod selections_collection;
18
19#[cfg(test)]
20mod editor_tests;
21#[cfg(any(test, feature = "test-support"))]
22pub mod test;
23use aho_corasick::AhoCorasick;
24use anyhow::{Context as _, Result};
25use blink_manager::BlinkManager;
26use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings};
27use clock::ReplicaId;
28use collections::{BTreeMap, HashMap, HashSet, VecDeque};
29use copilot::Copilot;
30pub use display_map::DisplayPoint;
31use display_map::*;
32pub use editor_settings::EditorSettings;
33pub use element::{
34 Cursor, EditorElement, HighlightedRange, HighlightedRangeLine, LineWithInvisibles,
35};
36use futures::FutureExt;
37use fuzzy::{StringMatch, StringMatchCandidate};
38use gpui::{
39 div, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, EventEmitter,
40 FocusHandle, Hsla, Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View,
41 ViewContext, VisualContext, WeakView, WindowContext,
42};
43use highlight_matching_bracket::refresh_matching_bracket_highlights;
44use hover_popover::{hide_hover, HoverState};
45use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
46pub use items::MAX_TAB_TITLE_LEN;
47use itertools::Itertools;
48pub use language::{char_kind, CharKind};
49use language::{
50 language_settings::{self, all_language_settings, InlayHintSettings},
51 point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, Completion, CursorShape,
52 Diagnostic, Language, LanguageRegistry, LanguageServerName, OffsetRangeExt, Point, Selection,
53 SelectionGoal, TransactionId,
54};
55use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState};
56use lsp::{DiagnosticSeverity, Documentation, LanguageServerId};
57pub use multi_buffer::{
58 Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
59 ToPoint,
60};
61use ordered_float::OrderedFloat;
62use parking_lot::RwLock;
63use project::{FormatTrigger, Location, Project};
64use rpc::proto::*;
65use scroll::{
66 autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
67};
68use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
69use serde::{Deserialize, Serialize};
70use settings::{Settings, SettingsStore};
71use smallvec::SmallVec;
72use std::{
73 any::TypeId,
74 borrow::Cow,
75 cmp::{self, Ordering, Reverse},
76 ops::{ControlFlow, Deref, DerefMut, Range},
77 path::Path,
78 sync::Arc,
79 time::{Duration, Instant},
80};
81pub use sum_tree::Bias;
82use sum_tree::TreeMap;
83use text::Rope;
84use theme::{ActiveTheme, PlayerColor, ThemeColors, ThemeVariant};
85use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
86use workspace::{ItemNavHistory, SplitDirection, ViewId, Workspace};
87
88const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
89const MAX_LINE_LEN: usize = 1024;
90const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
91const MAX_SELECTION_HISTORY_LEN: usize = 1024;
92const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
93pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
94pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
95
96pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
97
98// pub fn render_parsed_markdown<Tag: 'static>(
99// parsed: &language::ParsedMarkdown,
100// editor_style: &EditorStyle,
101// workspace: Option<WeakView<Workspace>>,
102// cx: &mut ViewContext<Editor>,
103// ) -> Text {
104// enum RenderedMarkdown {}
105
106// let parsed = parsed.clone();
107// let view_id = cx.view_id();
108// let code_span_background_color = editor_style.document_highlight_read_background;
109
110// let mut region_id = 0;
111
112// todo!()
113// // Text::new(parsed.text, editor_style.text.clone())
114// // .with_highlights(
115// // parsed
116// // .highlights
117// // .iter()
118// // .filter_map(|(range, highlight)| {
119// // let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
120// // Some((range.clone(), highlight))
121// // })
122// // .collect::<Vec<_>>(),
123// // )
124// // .with_custom_runs(parsed.region_ranges, move |ix, bounds, cx| {
125// // region_id += 1;
126// // let region = parsed.regions[ix].clone();
127
128// // if let Some(link) = region.link {
129// // cx.scene().push_cursor_region(CursorRegion {
130// // bounds,
131// // style: CursorStyle::PointingHand,
132// // });
133// // cx.scene().push_mouse_region(
134// // MouseRegion::new::<(RenderedMarkdown, Tag)>(view_id, region_id, bounds)
135// // .on_down::<Editor, _>(MouseButton::Left, move |_, _, cx| match &link {
136// // markdown::Link::Web { url } => cx.platform().open_url(url),
137// // markdown::Link::Path { path } => {
138// // if let Some(workspace) = &workspace {
139// // _ = workspace.update(cx, |workspace, cx| {
140// // workspace.open_abs_path(path.clone(), false, cx).detach();
141// // });
142// // }
143// // }
144// // }),
145// // );
146// // }
147
148// // if region.code {
149// // cx.draw_quad(Quad {
150// // bounds,
151// // background: Some(code_span_background_color),
152// // corner_radii: (2.0).into(),
153// // order: todo!(),
154// // content_mask: todo!(),
155// // border_color: todo!(),
156// // border_widths: todo!(),
157// // });
158// // }
159// // })
160// // .with_soft_wrap(true)
161// }
162
163#[derive(Clone, Deserialize, PartialEq, Default)]
164pub struct SelectNext {
165 #[serde(default)]
166 pub replace_newest: bool,
167}
168
169#[derive(Clone, Deserialize, PartialEq, Default)]
170pub struct SelectPrevious {
171 #[serde(default)]
172 pub replace_newest: bool,
173}
174
175#[derive(Clone, Deserialize, PartialEq, Default)]
176pub struct SelectAllMatches {
177 #[serde(default)]
178 pub replace_newest: bool,
179}
180
181#[derive(Clone, Deserialize, PartialEq)]
182pub struct SelectToBeginningOfLine {
183 #[serde(default)]
184 stop_at_soft_wraps: bool,
185}
186
187#[derive(Clone, Default, Deserialize, PartialEq)]
188pub struct MovePageUp {
189 #[serde(default)]
190 center_cursor: bool,
191}
192
193#[derive(Clone, Default, Deserialize, PartialEq)]
194pub struct MovePageDown {
195 #[serde(default)]
196 center_cursor: bool,
197}
198
199#[derive(Clone, Deserialize, PartialEq)]
200pub struct SelectToEndOfLine {
201 #[serde(default)]
202 stop_at_soft_wraps: bool,
203}
204
205#[derive(Clone, Deserialize, PartialEq)]
206pub struct ToggleCodeActions {
207 #[serde(default)]
208 pub deployed_from_indicator: bool,
209}
210
211#[derive(Clone, Default, Deserialize, PartialEq)]
212pub struct ConfirmCompletion {
213 #[serde(default)]
214 pub item_ix: Option<usize>,
215}
216
217#[derive(Clone, Default, Deserialize, PartialEq)]
218pub struct ConfirmCodeAction {
219 #[serde(default)]
220 pub item_ix: Option<usize>,
221}
222
223#[derive(Clone, Default, Deserialize, PartialEq)]
224pub struct ToggleComments {
225 #[serde(default)]
226 pub advance_downwards: bool,
227}
228
229#[derive(Clone, Default, Deserialize, PartialEq)]
230pub struct FoldAt {
231 pub buffer_row: u32,
232}
233
234#[derive(Clone, Default, Deserialize, PartialEq)]
235pub struct UnfoldAt {
236 pub buffer_row: u32,
237}
238
239#[derive(Clone, Default, Deserialize, PartialEq)]
240pub struct GutterHover {
241 pub hovered: bool,
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
245pub enum InlayId {
246 Suggestion(usize),
247 Hint(usize),
248}
249
250impl InlayId {
251 fn id(&self) -> usize {
252 match self {
253 Self::Suggestion(id) => *id,
254 Self::Hint(id) => *id,
255 }
256 }
257}
258
259// actions!(
260// editor,
261// [
262// Cancel,
263// Backspace,
264// Delete,
265// Newline,
266// NewlineAbove,
267// NewlineBelow,
268// GoToDiagnostic,
269// GoToPrevDiagnostic,
270// GoToHunk,
271// GoToPrevHunk,
272// Indent,
273// Outdent,
274// DeleteLine,
275// DeleteToPreviousWordStart,
276// DeleteToPreviousSubwordStart,
277// DeleteToNextWordEnd,
278// DeleteToNextSubwordEnd,
279// DeleteToBeginningOfLine,
280// DeleteToEndOfLine,
281// CutToEndOfLine,
282// DuplicateLine,
283// MoveLineUp,
284// MoveLineDown,
285// JoinLines,
286// SortLinesCaseSensitive,
287// SortLinesCaseInsensitive,
288// ReverseLines,
289// ShuffleLines,
290// ConvertToUpperCase,
291// ConvertToLowerCase,
292// ConvertToTitleCase,
293// ConvertToSnakeCase,
294// ConvertToKebabCase,
295// ConvertToUpperCamelCase,
296// ConvertToLowerCamelCase,
297// Transpose,
298// Cut,
299// Copy,
300// Paste,
301// Undo,
302// Redo,
303// MoveUp,
304// PageUp,
305// MoveDown,
306// PageDown,
307// MoveLeft,
308// MoveRight,
309// MoveToPreviousWordStart,
310// MoveToPreviousSubwordStart,
311// MoveToNextWordEnd,
312// MoveToNextSubwordEnd,
313// MoveToBeginningOfLine,
314// MoveToEndOfLine,
315// MoveToStartOfParagraph,
316// MoveToEndOfParagraph,
317// MoveToBeginning,
318// MoveToEnd,
319// SelectUp,
320// SelectDown,
321// SelectLeft,
322// SelectRight,
323// SelectToPreviousWordStart,
324// SelectToPreviousSubwordStart,
325// SelectToNextWordEnd,
326// SelectToNextSubwordEnd,
327// SelectToStartOfParagraph,
328// SelectToEndOfParagraph,
329// SelectToBeginning,
330// SelectToEnd,
331// SelectAll,
332// SelectLine,
333// SplitSelectionIntoLines,
334// AddSelectionAbove,
335// AddSelectionBelow,
336// Tab,
337// TabPrev,
338// ShowCharacterPalette,
339// SelectLargerSyntaxNode,
340// SelectSmallerSyntaxNode,
341// GoToDefinition,
342// GoToDefinitionSplit,
343// GoToTypeDefinition,
344// GoToTypeDefinitionSplit,
345// MoveToEnclosingBracket,
346// UndoSelection,
347// RedoSelection,
348// FindAllReferences,
349// Rename,
350// ConfirmRename,
351// Fold,
352// UnfoldLines,
353// FoldSelectedRanges,
354// ShowCompletions,
355// OpenExcerpts,
356// RestartLanguageServer,
357// Hover,
358// Format,
359// ToggleSoftWrap,
360// ToggleInlayHints,
361// RevealInFinder,
362// CopyPath,
363// CopyRelativePath,
364// CopyHighlightJson,
365// ContextMenuFirst,
366// ContextMenuPrev,
367// ContextMenuNext,
368// ContextMenuLast,
369// ]
370// );
371
372// impl_actions!(
373// editor,
374// [
375// SelectNext,
376// SelectPrevious,
377// SelectAllMatches,
378// SelectToBeginningOfLine,
379// SelectToEndOfLine,
380// ToggleCodeActions,
381// MovePageUp,
382// MovePageDown,
383// ConfirmCompletion,
384// ConfirmCodeAction,
385// ToggleComments,
386// FoldAt,
387// UnfoldAt,
388// GutterHover
389// ]
390// );
391
392// todo!(revisit these actions)
393pub struct ShowCompletions;
394pub struct Rename;
395pub struct GoToDefinition;
396pub struct GoToTypeDefinition;
397pub struct GoToDefinitionSplit;
398pub struct GoToTypeDefinitionSplit;
399
400enum DocumentHighlightRead {}
401enum DocumentHighlightWrite {}
402enum InputComposition {}
403
404#[derive(Copy, Clone, PartialEq, Eq)]
405pub enum Direction {
406 Prev,
407 Next,
408}
409
410pub fn init_settings(cx: &mut AppContext) {
411 EditorSettings::register(cx);
412}
413
414pub fn init(cx: &mut AppContext) {
415 init_settings(cx);
416 // cx.add_action(Editor::new_file);
417 // cx.add_action(Editor::new_file_in_direction);
418 // cx.add_action(Editor::cancel);
419 // cx.add_action(Editor::newline);
420 // cx.add_action(Editor::newline_above);
421 // cx.add_action(Editor::newline_below);
422 // cx.add_action(Editor::backspace);
423 // cx.add_action(Editor::delete);
424 // cx.add_action(Editor::tab);
425 // cx.add_action(Editor::tab_prev);
426 // cx.add_action(Editor::indent);
427 // cx.add_action(Editor::outdent);
428 // cx.add_action(Editor::delete_line);
429 // cx.add_action(Editor::join_lines);
430 // cx.add_action(Editor::sort_lines_case_sensitive);
431 // cx.add_action(Editor::sort_lines_case_insensitive);
432 // cx.add_action(Editor::reverse_lines);
433 // cx.add_action(Editor::shuffle_lines);
434 // cx.add_action(Editor::convert_to_upper_case);
435 // cx.add_action(Editor::convert_to_lower_case);
436 // cx.add_action(Editor::convert_to_title_case);
437 // cx.add_action(Editor::convert_to_snake_case);
438 // cx.add_action(Editor::convert_to_kebab_case);
439 // cx.add_action(Editor::convert_to_upper_camel_case);
440 // cx.add_action(Editor::convert_to_lower_camel_case);
441 // cx.add_action(Editor::delete_to_previous_word_start);
442 // cx.add_action(Editor::delete_to_previous_subword_start);
443 // cx.add_action(Editor::delete_to_next_word_end);
444 // cx.add_action(Editor::delete_to_next_subword_end);
445 // cx.add_action(Editor::delete_to_beginning_of_line);
446 // cx.add_action(Editor::delete_to_end_of_line);
447 // cx.add_action(Editor::cut_to_end_of_line);
448 // cx.add_action(Editor::duplicate_line);
449 // cx.add_action(Editor::move_line_up);
450 // cx.add_action(Editor::move_line_down);
451 // cx.add_action(Editor::transpose);
452 // cx.add_action(Editor::cut);
453 // cx.add_action(Editor::copy);
454 // cx.add_action(Editor::paste);
455 // cx.add_action(Editor::undo);
456 // cx.add_action(Editor::redo);
457 // cx.add_action(Editor::move_up);
458 // cx.add_action(Editor::move_page_up);
459 // cx.add_action(Editor::move_down);
460 // cx.add_action(Editor::move_page_down);
461 // cx.add_action(Editor::next_screen);
462 // cx.add_action(Editor::move_left);
463 // cx.add_action(Editor::move_right);
464 // cx.add_action(Editor::move_to_previous_word_start);
465 // cx.add_action(Editor::move_to_previous_subword_start);
466 // cx.add_action(Editor::move_to_next_word_end);
467 // cx.add_action(Editor::move_to_next_subword_end);
468 // cx.add_action(Editor::move_to_beginning_of_line);
469 // cx.add_action(Editor::move_to_end_of_line);
470 // cx.add_action(Editor::move_to_start_of_paragraph);
471 // cx.add_action(Editor::move_to_end_of_paragraph);
472 // cx.add_action(Editor::move_to_beginning);
473 // cx.add_action(Editor::move_to_end);
474 // cx.add_action(Editor::select_up);
475 // cx.add_action(Editor::select_down);
476 // cx.add_action(Editor::select_left);
477 // cx.add_action(Editor::select_right);
478 // cx.add_action(Editor::select_to_previous_word_start);
479 // cx.add_action(Editor::select_to_previous_subword_start);
480 // cx.add_action(Editor::select_to_next_word_end);
481 // cx.add_action(Editor::select_to_next_subword_end);
482 // cx.add_action(Editor::select_to_beginning_of_line);
483 // cx.add_action(Editor::select_to_end_of_line);
484 // cx.add_action(Editor::select_to_start_of_paragraph);
485 // cx.add_action(Editor::select_to_end_of_paragraph);
486 // cx.add_action(Editor::select_to_beginning);
487 // cx.add_action(Editor::select_to_end);
488 // cx.add_action(Editor::select_all);
489 // cx.add_action(Editor::select_all_matches);
490 // cx.add_action(Editor::select_line);
491 // cx.add_action(Editor::split_selection_into_lines);
492 // cx.add_action(Editor::add_selection_above);
493 // cx.add_action(Editor::add_selection_below);
494 // cx.add_action(Editor::select_next);
495 // cx.add_action(Editor::select_previous);
496 // cx.add_action(Editor::toggle_comments);
497 // cx.add_action(Editor::select_larger_syntax_node);
498 // cx.add_action(Editor::select_smaller_syntax_node);
499 // cx.add_action(Editor::move_to_enclosing_bracket);
500 // cx.add_action(Editor::undo_selection);
501 // cx.add_action(Editor::redo_selection);
502 // cx.add_action(Editor::go_to_diagnostic);
503 // cx.add_action(Editor::go_to_prev_diagnostic);
504 // cx.add_action(Editor::go_to_hunk);
505 // cx.add_action(Editor::go_to_prev_hunk);
506 // cx.add_action(Editor::go_to_definition);
507 // cx.add_action(Editor::go_to_definition_split);
508 // cx.add_action(Editor::go_to_type_definition);
509 // cx.add_action(Editor::go_to_type_definition_split);
510 // cx.add_action(Editor::fold);
511 // cx.add_action(Editor::fold_at);
512 // cx.add_action(Editor::unfold_lines);
513 // cx.add_action(Editor::unfold_at);
514 // cx.add_action(Editor::gutter_hover);
515 // cx.add_action(Editor::fold_selected_ranges);
516 // cx.add_action(Editor::show_completions);
517 // cx.add_action(Editor::toggle_code_actions);
518 // cx.add_action(Editor::open_excerpts);
519 // cx.add_action(Editor::toggle_soft_wrap);
520 // cx.add_action(Editor::toggle_inlay_hints);
521 // cx.add_action(Editor::reveal_in_finder);
522 // cx.add_action(Editor::copy_path);
523 // cx.add_action(Editor::copy_relative_path);
524 // cx.add_action(Editor::copy_highlight_json);
525 // cx.add_async_action(Editor::format);
526 // cx.add_action(Editor::restart_language_server);
527 // cx.add_action(Editor::show_character_palette);
528 // cx.add_async_action(Editor::confirm_completion);
529 // cx.add_async_action(Editor::confirm_code_action);
530 // cx.add_async_action(Editor::rename);
531 // cx.add_async_action(Editor::confirm_rename);
532 // cx.add_async_action(Editor::find_all_references);
533 // cx.add_action(Editor::next_copilot_suggestion);
534 // cx.add_action(Editor::previous_copilot_suggestion);
535 // cx.add_action(Editor::copilot_suggest);
536 // cx.add_action(Editor::context_menu_first);
537 // cx.add_action(Editor::context_menu_prev);
538 // cx.add_action(Editor::context_menu_next);
539 // cx.add_action(Editor::context_menu_last);
540
541 hover_popover::init(cx);
542 scroll::actions::init(cx);
543
544 workspace::register_project_item::<Editor>(cx);
545 workspace::register_followable_item::<Editor>(cx);
546 workspace::register_deserializable_item::<Editor>(cx);
547}
548
549trait InvalidationRegion {
550 fn ranges(&self) -> &[Range<Anchor>];
551}
552
553#[derive(Clone, Debug, PartialEq)]
554pub enum SelectPhase {
555 Begin {
556 position: DisplayPoint,
557 add: bool,
558 click_count: usize,
559 },
560 BeginColumnar {
561 position: DisplayPoint,
562 goal_column: u32,
563 },
564 Extend {
565 position: DisplayPoint,
566 click_count: usize,
567 },
568 Update {
569 position: DisplayPoint,
570 goal_column: u32,
571 scroll_position: gpui::Point<f32>,
572 },
573 End,
574}
575
576#[derive(Clone, Debug)]
577pub enum SelectMode {
578 Character,
579 Word(Range<Anchor>),
580 Line(Range<Anchor>),
581 All,
582}
583
584#[derive(Copy, Clone, PartialEq, Eq, Debug)]
585pub enum EditorMode {
586 SingleLine,
587 AutoHeight { max_lines: usize },
588 Full,
589}
590
591#[derive(Clone, Debug)]
592pub enum SoftWrap {
593 None,
594 EditorWidth,
595 Column(u32),
596}
597
598#[derive(Clone)]
599pub struct EditorStyle {
600 pub local_player: PlayerColor,
601 pub text: TextStyle,
602 pub line_height_scalar: f32,
603 // pub placeholder_text: Option<TextStyle>,
604 // pub theme: theme::Editor,
605 pub theme_id: usize,
606}
607
608type CompletionId = usize;
609
610// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
611// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
612
613type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>);
614type InlayBackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<InlayHighlight>);
615
616pub struct Editor {
617 handle: WeakView<Self>,
618 focus_handle: FocusHandle,
619 buffer: Model<MultiBuffer>,
620 display_map: Model<DisplayMap>,
621 pub selections: SelectionsCollection,
622 pub scroll_manager: ScrollManager,
623 columnar_selection_tail: Option<Anchor>,
624 add_selections_state: Option<AddSelectionsState>,
625 select_next_state: Option<SelectNextState>,
626 select_prev_state: Option<SelectNextState>,
627 selection_history: SelectionHistory,
628 autoclose_regions: Vec<AutocloseRegion>,
629 snippet_stack: InvalidationStack<SnippetState>,
630 select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
631 ime_transaction: Option<TransactionId>,
632 active_diagnostics: Option<ActiveDiagnosticGroup>,
633 soft_wrap_mode_override: Option<language_settings::SoftWrap>,
634 // get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
635 // override_text_style: Option<Box<OverrideTextStyle>>,
636 project: Option<Model<Project>>,
637 collaboration_hub: Option<Box<dyn CollaborationHub>>,
638 focused: bool,
639 blink_manager: Model<BlinkManager>,
640 pub show_local_selections: bool,
641 mode: EditorMode,
642 show_gutter: bool,
643 show_wrap_guides: Option<bool>,
644 placeholder_text: Option<Arc<str>>,
645 highlighted_rows: Option<Range<u32>>,
646 background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
647 inlay_background_highlights: TreeMap<Option<TypeId>, InlayBackgroundHighlight>,
648 nav_history: Option<ItemNavHistory>,
649 context_menu: RwLock<Option<ContextMenu>>,
650 // mouse_context_menu: View<context_menu::ContextMenu>,
651 completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
652 next_completion_id: CompletionId,
653 available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
654 code_actions_task: Option<Task<()>>,
655 document_highlights_task: Option<Task<()>>,
656 pending_rename: Option<RenameState>,
657 searchable: bool,
658 cursor_shape: CursorShape,
659 collapse_matches: bool,
660 autoindent_mode: Option<AutoindentMode>,
661 workspace: Option<(WeakView<Workspace>, i64)>,
662 // keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
663 input_enabled: bool,
664 read_only: bool,
665 leader_peer_id: Option<PeerId>,
666 remote_id: Option<ViewId>,
667 hover_state: HoverState,
668 gutter_hovered: bool,
669 link_go_to_definition_state: LinkGoToDefinitionState,
670 copilot_state: CopilotState,
671 inlay_hint_cache: InlayHintCache,
672 next_inlay_id: usize,
673 _subscriptions: Vec<Subscription>,
674 pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
675}
676
677pub struct EditorSnapshot {
678 pub mode: EditorMode,
679 pub show_gutter: bool,
680 pub display_snapshot: DisplaySnapshot,
681 pub placeholder_text: Option<Arc<str>>,
682 is_focused: bool,
683 scroll_anchor: ScrollAnchor,
684 ongoing_scroll: OngoingScroll,
685}
686
687pub struct RemoteSelection {
688 pub replica_id: ReplicaId,
689 pub selection: Selection<Anchor>,
690 pub cursor_shape: CursorShape,
691 pub peer_id: PeerId,
692 pub line_mode: bool,
693 pub participant_index: Option<ParticipantIndex>,
694}
695
696#[derive(Clone, Debug)]
697struct SelectionHistoryEntry {
698 selections: Arc<[Selection<Anchor>]>,
699 select_next_state: Option<SelectNextState>,
700 select_prev_state: Option<SelectNextState>,
701 add_selections_state: Option<AddSelectionsState>,
702}
703
704enum SelectionHistoryMode {
705 Normal,
706 Undoing,
707 Redoing,
708}
709
710impl Default for SelectionHistoryMode {
711 fn default() -> Self {
712 Self::Normal
713 }
714}
715
716#[derive(Default)]
717struct SelectionHistory {
718 #[allow(clippy::type_complexity)]
719 selections_by_transaction:
720 HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
721 mode: SelectionHistoryMode,
722 undo_stack: VecDeque<SelectionHistoryEntry>,
723 redo_stack: VecDeque<SelectionHistoryEntry>,
724}
725
726impl SelectionHistory {
727 fn insert_transaction(
728 &mut self,
729 transaction_id: TransactionId,
730 selections: Arc<[Selection<Anchor>]>,
731 ) {
732 self.selections_by_transaction
733 .insert(transaction_id, (selections, None));
734 }
735
736 #[allow(clippy::type_complexity)]
737 fn transaction(
738 &self,
739 transaction_id: TransactionId,
740 ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
741 self.selections_by_transaction.get(&transaction_id)
742 }
743
744 #[allow(clippy::type_complexity)]
745 fn transaction_mut(
746 &mut self,
747 transaction_id: TransactionId,
748 ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
749 self.selections_by_transaction.get_mut(&transaction_id)
750 }
751
752 fn push(&mut self, entry: SelectionHistoryEntry) {
753 if !entry.selections.is_empty() {
754 match self.mode {
755 SelectionHistoryMode::Normal => {
756 self.push_undo(entry);
757 self.redo_stack.clear();
758 }
759 SelectionHistoryMode::Undoing => self.push_redo(entry),
760 SelectionHistoryMode::Redoing => self.push_undo(entry),
761 }
762 }
763 }
764
765 fn push_undo(&mut self, entry: SelectionHistoryEntry) {
766 if self
767 .undo_stack
768 .back()
769 .map_or(true, |e| e.selections != entry.selections)
770 {
771 self.undo_stack.push_back(entry);
772 if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
773 self.undo_stack.pop_front();
774 }
775 }
776 }
777
778 fn push_redo(&mut self, entry: SelectionHistoryEntry) {
779 if self
780 .redo_stack
781 .back()
782 .map_or(true, |e| e.selections != entry.selections)
783 {
784 self.redo_stack.push_back(entry);
785 if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
786 self.redo_stack.pop_front();
787 }
788 }
789 }
790}
791
792#[derive(Clone, Debug)]
793struct AddSelectionsState {
794 above: bool,
795 stack: Vec<usize>,
796}
797
798#[derive(Clone)]
799struct SelectNextState {
800 query: AhoCorasick,
801 wordwise: bool,
802 done: bool,
803}
804
805impl std::fmt::Debug for SelectNextState {
806 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
807 f.debug_struct(std::any::type_name::<Self>())
808 .field("wordwise", &self.wordwise)
809 .field("done", &self.done)
810 .finish()
811 }
812}
813
814#[derive(Debug)]
815struct AutocloseRegion {
816 selection_id: usize,
817 range: Range<Anchor>,
818 pair: BracketPair,
819}
820
821#[derive(Debug)]
822struct SnippetState {
823 ranges: Vec<Vec<Range<Anchor>>>,
824 active_index: usize,
825}
826
827pub struct RenameState {
828 pub range: Range<Anchor>,
829 pub old_name: Arc<str>,
830 pub editor: View<Editor>,
831 block_id: BlockId,
832}
833
834struct InvalidationStack<T>(Vec<T>);
835
836enum ContextMenu {
837 Completions(CompletionsMenu),
838 CodeActions(CodeActionsMenu),
839}
840
841impl ContextMenu {
842 fn select_first(
843 &mut self,
844 project: Option<&Model<Project>>,
845 cx: &mut ViewContext<Editor>,
846 ) -> bool {
847 if self.visible() {
848 match self {
849 ContextMenu::Completions(menu) => menu.select_first(project, cx),
850 ContextMenu::CodeActions(menu) => menu.select_first(cx),
851 }
852 true
853 } else {
854 false
855 }
856 }
857
858 fn select_prev(
859 &mut self,
860 project: Option<&Model<Project>>,
861 cx: &mut ViewContext<Editor>,
862 ) -> bool {
863 if self.visible() {
864 match self {
865 ContextMenu::Completions(menu) => menu.select_prev(project, cx),
866 ContextMenu::CodeActions(menu) => menu.select_prev(cx),
867 }
868 true
869 } else {
870 false
871 }
872 }
873
874 fn select_next(
875 &mut self,
876 project: Option<&Model<Project>>,
877 cx: &mut ViewContext<Editor>,
878 ) -> bool {
879 if self.visible() {
880 match self {
881 ContextMenu::Completions(menu) => menu.select_next(project, cx),
882 ContextMenu::CodeActions(menu) => menu.select_next(cx),
883 }
884 true
885 } else {
886 false
887 }
888 }
889
890 fn select_last(
891 &mut self,
892 project: Option<&Model<Project>>,
893 cx: &mut ViewContext<Editor>,
894 ) -> bool {
895 if self.visible() {
896 match self {
897 ContextMenu::Completions(menu) => menu.select_last(project, cx),
898 ContextMenu::CodeActions(menu) => menu.select_last(cx),
899 }
900 true
901 } else {
902 false
903 }
904 }
905
906 fn visible(&self) -> bool {
907 match self {
908 ContextMenu::Completions(menu) => menu.visible(),
909 ContextMenu::CodeActions(menu) => menu.visible(),
910 }
911 }
912
913 fn render(
914 &self,
915 cursor_position: DisplayPoint,
916 style: EditorStyle,
917 workspace: Option<WeakView<Workspace>>,
918 cx: &mut ViewContext<Editor>,
919 ) -> (DisplayPoint, AnyElement<Editor>) {
920 todo!()
921 // match self {
922 // ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)),
923 // ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
924 // }
925 }
926}
927
928#[derive(Clone)]
929struct CompletionsMenu {
930 id: CompletionId,
931 initial_position: Anchor,
932 buffer: Model<Buffer>,
933 completions: Arc<RwLock<Box<[Completion]>>>,
934 match_candidates: Arc<[StringMatchCandidate]>,
935 matches: Arc<[StringMatch]>,
936 selected_item: usize,
937 list: UniformListState,
938}
939
940// todo!(this is fake)
941#[derive(Clone, Default)]
942struct UniformListState;
943
944// todo!(this is fake)
945impl UniformListState {
946 pub fn scroll_to(&mut self, target: ScrollTarget) {}
947}
948
949// todo!(this is somewhat fake)
950#[derive(Debug)]
951pub enum ScrollTarget {
952 Show(usize),
953 Center(usize),
954}
955
956impl CompletionsMenu {
957 fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
958 self.selected_item = 0;
959 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
960 self.attempt_resolve_selected_completion_documentation(project, cx);
961 cx.notify();
962 }
963
964 fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
965 if self.selected_item > 0 {
966 self.selected_item -= 1;
967 } else {
968 self.selected_item = self.matches.len() - 1;
969 }
970 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
971 self.attempt_resolve_selected_completion_documentation(project, cx);
972 cx.notify();
973 }
974
975 fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
976 if self.selected_item + 1 < self.matches.len() {
977 self.selected_item += 1;
978 } else {
979 self.selected_item = 0;
980 }
981 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
982 self.attempt_resolve_selected_completion_documentation(project, cx);
983 cx.notify();
984 }
985
986 fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
987 self.selected_item = self.matches.len() - 1;
988 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
989 self.attempt_resolve_selected_completion_documentation(project, cx);
990 cx.notify();
991 }
992
993 fn pre_resolve_completion_documentation(
994 &self,
995 project: Option<Model<Project>>,
996 cx: &mut ViewContext<Editor>,
997 ) {
998 todo!("implementation below ");
999 }
1000 // ) {
1001 // let settings = EditorSettings::get_global(cx);
1002 // if !settings.show_completion_documentation {
1003 // return;
1004 // }
1005
1006 // let Some(project) = project else {
1007 // return;
1008 // };
1009 // let client = project.read(cx).client();
1010 // let language_registry = project.read(cx).languages().clone();
1011
1012 // let is_remote = project.read(cx).is_remote();
1013 // let project_id = project.read(cx).remote_id();
1014
1015 // let completions = self.completions.clone();
1016 // let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
1017
1018 // cx.spawn(move |this, mut cx| async move {
1019 // if is_remote {
1020 // let Some(project_id) = project_id else {
1021 // log::error!("Remote project without remote_id");
1022 // return;
1023 // };
1024
1025 // for completion_index in completion_indices {
1026 // let completions_guard = completions.read();
1027 // let completion = &completions_guard[completion_index];
1028 // if completion.documentation.is_some() {
1029 // continue;
1030 // }
1031
1032 // let server_id = completion.server_id;
1033 // let completion = completion.lsp_completion.clone();
1034 // drop(completions_guard);
1035
1036 // Self::resolve_completion_documentation_remote(
1037 // project_id,
1038 // server_id,
1039 // completions.clone(),
1040 // completion_index,
1041 // completion,
1042 // client.clone(),
1043 // language_registry.clone(),
1044 // )
1045 // .await;
1046
1047 // _ = this.update(&mut cx, |_, cx| cx.notify());
1048 // }
1049 // } else {
1050 // for completion_index in completion_indices {
1051 // let completions_guard = completions.read();
1052 // let completion = &completions_guard[completion_index];
1053 // if completion.documentation.is_some() {
1054 // continue;
1055 // }
1056
1057 // let server_id = completion.server_id;
1058 // let completion = completion.lsp_completion.clone();
1059 // drop(completions_guard);
1060
1061 // let server = project.read_with(&mut cx, |project, _| {
1062 // project.language_server_for_id(server_id)
1063 // });
1064 // let Some(server) = server else {
1065 // return;
1066 // };
1067
1068 // Self::resolve_completion_documentation_local(
1069 // server,
1070 // completions.clone(),
1071 // completion_index,
1072 // completion,
1073 // language_registry.clone(),
1074 // )
1075 // .await;
1076
1077 // _ = this.update(&mut cx, |_, cx| cx.notify());
1078 // }
1079 // }
1080 // })
1081 // .detach();
1082 // }
1083
1084 fn attempt_resolve_selected_completion_documentation(
1085 &mut self,
1086 project: Option<&Model<Project>>,
1087 cx: &mut ViewContext<Editor>,
1088 ) {
1089 let settings = EditorSettings::get_global(cx);
1090 if !settings.show_completion_documentation {
1091 return;
1092 }
1093
1094 let completion_index = self.matches[self.selected_item].candidate_id;
1095 let Some(project) = project else {
1096 return;
1097 };
1098 let language_registry = project.read(cx).languages().clone();
1099
1100 let completions = self.completions.clone();
1101 let completions_guard = completions.read();
1102 let completion = &completions_guard[completion_index];
1103 // todo!()
1104 // if completion.documentation.is_some() {
1105 // return;
1106 // }
1107
1108 let server_id = completion.server_id;
1109 let completion = completion.lsp_completion.clone();
1110 drop(completions_guard);
1111
1112 if project.read(cx).is_remote() {
1113 let Some(project_id) = project.read(cx).remote_id() else {
1114 log::error!("Remote project without remote_id");
1115 return;
1116 };
1117
1118 let client = project.read(cx).client();
1119
1120 cx.spawn(move |this, mut cx| async move {
1121 Self::resolve_completion_documentation_remote(
1122 project_id,
1123 server_id,
1124 completions.clone(),
1125 completion_index,
1126 completion,
1127 client,
1128 language_registry.clone(),
1129 )
1130 .await;
1131
1132 _ = this.update(&mut cx, |_, cx| cx.notify());
1133 })
1134 .detach();
1135 } else {
1136 let Some(server) = project.read(cx).language_server_for_id(server_id) else {
1137 return;
1138 };
1139
1140 cx.spawn(move |this, mut cx| async move {
1141 Self::resolve_completion_documentation_local(
1142 server,
1143 completions,
1144 completion_index,
1145 completion,
1146 language_registry,
1147 )
1148 .await;
1149
1150 _ = this.update(&mut cx, |_, cx| cx.notify());
1151 })
1152 .detach();
1153 }
1154 }
1155
1156 async fn resolve_completion_documentation_remote(
1157 project_id: u64,
1158 server_id: LanguageServerId,
1159 completions: Arc<RwLock<Box<[Completion]>>>,
1160 completion_index: usize,
1161 completion: lsp::CompletionItem,
1162 client: Arc<Client>,
1163 language_registry: Arc<LanguageRegistry>,
1164 ) {
1165 todo!()
1166 // let request = proto::ResolveCompletionDocumentation {
1167 // project_id,
1168 // language_server_id: server_id.0 as u64,
1169 // lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
1170 // };
1171
1172 // let Some(response) = client
1173 // .request(request)
1174 // .await
1175 // .context("completion documentation resolve proto request")
1176 // .log_err()
1177 // else {
1178 // return;
1179 // };
1180
1181 // if response.text.is_empty() {
1182 // let mut completions = completions.write();
1183 // let completion = &mut completions[completion_index];
1184 // completion.documentation = Some(Documentation::Undocumented);
1185 // }
1186
1187 // let documentation = if response.is_markdown {
1188 // Documentation::MultiLineMarkdown(
1189 // markdown::parse_markdown(&response.text, &language_registry, None).await,
1190 // )
1191 // } else if response.text.lines().count() <= 1 {
1192 // Documentation::SingleLine(response.text)
1193 // } else {
1194 // Documentation::MultiLinePlainText(response.text)
1195 // };
1196
1197 // let mut completions = completions.write();
1198 // let completion = &mut completions[completion_index];
1199 // completion.documentation = Some(documentation);
1200 }
1201
1202 async fn resolve_completion_documentation_local(
1203 server: Arc<lsp::LanguageServer>,
1204 completions: Arc<RwLock<Box<[Completion]>>>,
1205 completion_index: usize,
1206 completion: lsp::CompletionItem,
1207 language_registry: Arc<LanguageRegistry>,
1208 ) {
1209 todo!()
1210 // let can_resolve = server
1211 // .capabilities()
1212 // .completion_provider
1213 // .as_ref()
1214 // .and_then(|options| options.resolve_provider)
1215 // .unwrap_or(false);
1216 // if !can_resolve {
1217 // return;
1218 // }
1219
1220 // let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
1221 // let Some(completion_item) = request.await.log_err() else {
1222 // return;
1223 // };
1224
1225 // if let Some(lsp_documentation) = completion_item.documentation {
1226 // let documentation = language::prepare_completion_documentation(
1227 // &lsp_documentation,
1228 // &language_registry,
1229 // None, // TODO: Try to reasonably work out which language the completion is for
1230 // )
1231 // .await;
1232
1233 // let mut completions = completions.write();
1234 // let completion = &mut completions[completion_index];
1235 // completion.documentation = Some(documentation);
1236 // } else {
1237 // let mut completions = completions.write();
1238 // let completion = &mut completions[completion_index];
1239 // completion.documentation = Some(Documentation::Undocumented);
1240 // }
1241 }
1242
1243 fn visible(&self) -> bool {
1244 !self.matches.is_empty()
1245 }
1246
1247 fn render(
1248 &self,
1249 style: EditorStyle,
1250 workspace: Option<WeakView<Workspace>>,
1251 cx: &mut ViewContext<Editor>,
1252 ) {
1253 todo!("old implementation below")
1254 }
1255 // ) -> AnyElement<Editor> {
1256 // enum CompletionTag {}
1257
1258 // let settings = EditorSettings>(cx);
1259 // let show_completion_documentation = settings.show_completion_documentation;
1260
1261 // let widest_completion_ix = self
1262 // .matches
1263 // .iter()
1264 // .enumerate()
1265 // .max_by_key(|(_, mat)| {
1266 // let completions = self.completions.read();
1267 // let completion = &completions[mat.candidate_id];
1268 // let documentation = &completion.documentation;
1269
1270 // let mut len = completion.label.text.chars().count();
1271 // if let Some(Documentation::SingleLine(text)) = documentation {
1272 // if show_completion_documentation {
1273 // len += text.chars().count();
1274 // }
1275 // }
1276
1277 // len
1278 // })
1279 // .map(|(ix, _)| ix);
1280
1281 // let completions = self.completions.clone();
1282 // let matches = self.matches.clone();
1283 // let selected_item = self.selected_item;
1284
1285 // let list = UniformList::new(self.list.clone(), matches.len(), cx, {
1286 // let style = style.clone();
1287 // move |_, range, items, cx| {
1288 // let start_ix = range.start;
1289 // let completions_guard = completions.read();
1290
1291 // for (ix, mat) in matches[range].iter().enumerate() {
1292 // let item_ix = start_ix + ix;
1293 // let candidate_id = mat.candidate_id;
1294 // let completion = &completions_guard[candidate_id];
1295
1296 // let documentation = if show_completion_documentation {
1297 // &completion.documentation
1298 // } else {
1299 // &None
1300 // };
1301
1302 // items.push(
1303 // MouseEventHandler::new::<CompletionTag, _>(
1304 // mat.candidate_id,
1305 // cx,
1306 // |state, _| {
1307 // let item_style = if item_ix == selected_item {
1308 // style.autocomplete.selected_item
1309 // } else if state.hovered() {
1310 // style.autocomplete.hovered_item
1311 // } else {
1312 // style.autocomplete.item
1313 // };
1314
1315 // let completion_label =
1316 // Text::new(completion.label.text.clone(), style.text.clone())
1317 // .with_soft_wrap(false)
1318 // .with_highlights(
1319 // combine_syntax_and_fuzzy_match_highlights(
1320 // &completion.label.text,
1321 // style.text.color.into(),
1322 // styled_runs_for_code_label(
1323 // &completion.label,
1324 // &style.syntax,
1325 // ),
1326 // &mat.positions,
1327 // ),
1328 // );
1329
1330 // if let Some(Documentation::SingleLine(text)) = documentation {
1331 // Flex::row()
1332 // .with_child(completion_label)
1333 // .with_children((|| {
1334 // let text_style = TextStyle {
1335 // color: style.autocomplete.inline_docs_color,
1336 // font_size: style.text.font_size
1337 // * style.autocomplete.inline_docs_size_percent,
1338 // ..style.text.clone()
1339 // };
1340
1341 // let label = Text::new(text.clone(), text_style)
1342 // .aligned()
1343 // .constrained()
1344 // .dynamically(move |constraint, _, _| {
1345 // gpui::SizeConstraint {
1346 // min: constraint.min,
1347 // max: vec2f(
1348 // constraint.max.x(),
1349 // constraint.min.y(),
1350 // ),
1351 // }
1352 // });
1353
1354 // if Some(item_ix) == widest_completion_ix {
1355 // Some(
1356 // label
1357 // .contained()
1358 // .with_style(
1359 // style
1360 // .autocomplete
1361 // .inline_docs_container,
1362 // )
1363 // .into_any(),
1364 // )
1365 // } else {
1366 // Some(label.flex_float().into_any())
1367 // }
1368 // })())
1369 // .into_any()
1370 // } else {
1371 // completion_label.into_any()
1372 // }
1373 // .contained()
1374 // .with_style(item_style)
1375 // .constrained()
1376 // .dynamically(
1377 // move |constraint, _, _| {
1378 // if Some(item_ix) == widest_completion_ix {
1379 // constraint
1380 // } else {
1381 // gpui::SizeConstraint {
1382 // min: constraint.min,
1383 // max: constraint.min,
1384 // }
1385 // }
1386 // },
1387 // )
1388 // },
1389 // )
1390 // .with_cursor_style(CursorStyle::PointingHand)
1391 // .on_down(MouseButton::Left, move |_, this, cx| {
1392 // this.confirm_completion(
1393 // &ConfirmCompletion {
1394 // item_ix: Some(item_ix),
1395 // },
1396 // cx,
1397 // )
1398 // .map(|task| task.detach());
1399 // })
1400 // .constrained()
1401 // .with_min_width(style.autocomplete.completion_min_width)
1402 // .with_max_width(style.autocomplete.completion_max_width)
1403 // .into_any(),
1404 // );
1405 // }
1406 // }
1407 // })
1408 // .with_width_from_item(widest_completion_ix);
1409
1410 // enum MultiLineDocumentation {}
1411
1412 // Flex::row()
1413 // .with_child(list.flex(1., false))
1414 // .with_children({
1415 // let mat = &self.matches[selected_item];
1416 // let completions = self.completions.read();
1417 // let completion = &completions[mat.candidate_id];
1418 // let documentation = &completion.documentation;
1419
1420 // match documentation {
1421 // Some(Documentation::MultiLinePlainText(text)) => Some(
1422 // Flex::column()
1423 // .scrollable::<MultiLineDocumentation>(0, None, cx)
1424 // .with_child(
1425 // Text::new(text.clone(), style.text.clone()).with_soft_wrap(true),
1426 // )
1427 // .contained()
1428 // .with_style(style.autocomplete.alongside_docs_container)
1429 // .constrained()
1430 // .with_max_width(style.autocomplete.alongside_docs_max_width)
1431 // .flex(1., false),
1432 // ),
1433
1434 // Some(Documentation::MultiLineMarkdown(parsed)) => Some(
1435 // Flex::column()
1436 // .scrollable::<MultiLineDocumentation>(0, None, cx)
1437 // .with_child(render_parsed_markdown::<MultiLineDocumentation>(
1438 // parsed, &style, workspace, cx,
1439 // ))
1440 // .contained()
1441 // .with_style(style.autocomplete.alongside_docs_container)
1442 // .constrained()
1443 // .with_max_width(style.autocomplete.alongside_docs_max_width)
1444 // .flex(1., false),
1445 // ),
1446
1447 // _ => None,
1448 // }
1449 // })
1450 // .contained()
1451 // .with_style(style.autocomplete.container)
1452 // .into_any()
1453 // }
1454
1455 pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
1456 let mut matches = if let Some(query) = query {
1457 fuzzy::match_strings(
1458 &self.match_candidates,
1459 query,
1460 query.chars().any(|c| c.is_uppercase()),
1461 100,
1462 &Default::default(),
1463 executor,
1464 )
1465 .await
1466 } else {
1467 self.match_candidates
1468 .iter()
1469 .enumerate()
1470 .map(|(candidate_id, candidate)| StringMatch {
1471 candidate_id,
1472 score: Default::default(),
1473 positions: Default::default(),
1474 string: candidate.string.clone(),
1475 })
1476 .collect()
1477 };
1478
1479 // Remove all candidates where the query's start does not match the start of any word in the candidate
1480 if let Some(query) = query {
1481 if let Some(query_start) = query.chars().next() {
1482 matches.retain(|string_match| {
1483 split_words(&string_match.string).any(|word| {
1484 // Check that the first codepoint of the word as lowercase matches the first
1485 // codepoint of the query as lowercase
1486 word.chars()
1487 .flat_map(|codepoint| codepoint.to_lowercase())
1488 .zip(query_start.to_lowercase())
1489 .all(|(word_cp, query_cp)| word_cp == query_cp)
1490 })
1491 });
1492 }
1493 }
1494
1495 let completions = self.completions.read();
1496 matches.sort_unstable_by_key(|mat| {
1497 let completion = &completions[mat.candidate_id];
1498 (
1499 completion.lsp_completion.sort_text.as_ref(),
1500 Reverse(OrderedFloat(mat.score)),
1501 completion.sort_key(),
1502 )
1503 });
1504 drop(completions);
1505
1506 for mat in &mut matches {
1507 let completions = self.completions.read();
1508 let filter_start = completions[mat.candidate_id].label.filter_range.start;
1509 for position in &mut mat.positions {
1510 *position += filter_start;
1511 }
1512 }
1513
1514 self.matches = matches.into();
1515 self.selected_item = 0;
1516 }
1517}
1518
1519#[derive(Clone)]
1520struct CodeActionsMenu {
1521 actions: Arc<[CodeAction]>,
1522 buffer: Model<Buffer>,
1523 selected_item: usize,
1524 list: UniformListState,
1525 deployed_from_indicator: bool,
1526}
1527
1528impl CodeActionsMenu {
1529 fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
1530 self.selected_item = 0;
1531 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
1532 cx.notify()
1533 }
1534
1535 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
1536 if self.selected_item > 0 {
1537 self.selected_item -= 1;
1538 } else {
1539 self.selected_item = self.actions.len() - 1;
1540 }
1541 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
1542 cx.notify();
1543 }
1544
1545 fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
1546 if self.selected_item + 1 < self.actions.len() {
1547 self.selected_item += 1;
1548 } else {
1549 self.selected_item = 0;
1550 }
1551 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
1552 cx.notify();
1553 }
1554
1555 fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
1556 self.selected_item = self.actions.len() - 1;
1557 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
1558 cx.notify()
1559 }
1560
1561 fn visible(&self) -> bool {
1562 !self.actions.is_empty()
1563 }
1564
1565 fn render(
1566 &self,
1567 mut cursor_position: DisplayPoint,
1568 style: EditorStyle,
1569 cx: &mut ViewContext<Editor>,
1570 ) -> (DisplayPoint, AnyElement<Editor>) {
1571 todo!("old version below")
1572 }
1573 // enum ActionTag {}
1574
1575 // let container_style = style.autocomplete.container;
1576 // let actions = self.actions.clone();
1577 // let selected_item = self.selected_item;
1578 // let element = UniformList::new(
1579 // self.list.clone(),
1580 // actions.len(),
1581 // cx,
1582 // move |_, range, items, cx| {
1583 // let start_ix = range.start;
1584 // for (ix, action) in actions[range].iter().enumerate() {
1585 // let item_ix = start_ix + ix;
1586 // items.push(
1587 // MouseEventHandler::new::<ActionTag, _>(item_ix, cx, |state, _| {
1588 // let item_style = if item_ix == selected_item {
1589 // style.autocomplete.selected_item
1590 // } else if state.hovered() {
1591 // style.autocomplete.hovered_item
1592 // } else {
1593 // style.autocomplete.item
1594 // };
1595
1596 // Text::new(action.lsp_action.title.clone(), style.text.clone())
1597 // .with_soft_wrap(false)
1598 // .contained()
1599 // .with_style(item_style)
1600 // })
1601 // .with_cursor_style(CursorStyle::PointingHand)
1602 // .on_down(MouseButton::Left, move |_, this, cx| {
1603 // let workspace = this
1604 // .workspace
1605 // .as_ref()
1606 // .and_then(|(workspace, _)| workspace.upgrade(cx));
1607 // cx.window_context().defer(move |cx| {
1608 // if let Some(workspace) = workspace {
1609 // workspace.update(cx, |workspace, cx| {
1610 // if let Some(task) = Editor::confirm_code_action(
1611 // workspace,
1612 // &ConfirmCodeAction {
1613 // item_ix: Some(item_ix),
1614 // },
1615 // cx,
1616 // ) {
1617 // task.detach_and_log_err(cx);
1618 // }
1619 // });
1620 // }
1621 // });
1622 // })
1623 // .into_any(),
1624 // );
1625 // }
1626 // },
1627 // )
1628 // .with_width_from_item(
1629 // self.actions
1630 // .iter()
1631 // .enumerate()
1632 // .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
1633 // .map(|(ix, _)| ix),
1634 // )
1635 // .contained()
1636 // .with_style(container_style)
1637 // .into_any();
1638
1639 // if self.deployed_from_indicator {
1640 // *cursor_position.column_mut() = 0;
1641 // }
1642
1643 // (cursor_position, element)
1644 // }
1645}
1646
1647pub struct CopilotState {
1648 excerpt_id: Option<ExcerptId>,
1649 pending_refresh: Task<Option<()>>,
1650 pending_cycling_refresh: Task<Option<()>>,
1651 cycled: bool,
1652 completions: Vec<copilot::Completion>,
1653 active_completion_index: usize,
1654 suggestion: Option<Inlay>,
1655}
1656
1657impl Default for CopilotState {
1658 fn default() -> Self {
1659 Self {
1660 excerpt_id: None,
1661 pending_cycling_refresh: Task::ready(Some(())),
1662 pending_refresh: Task::ready(Some(())),
1663 completions: Default::default(),
1664 active_completion_index: 0,
1665 cycled: false,
1666 suggestion: None,
1667 }
1668 }
1669}
1670
1671impl CopilotState {
1672 fn active_completion(&self) -> Option<&copilot::Completion> {
1673 self.completions.get(self.active_completion_index)
1674 }
1675
1676 fn text_for_active_completion(
1677 &self,
1678 cursor: Anchor,
1679 buffer: &MultiBufferSnapshot,
1680 ) -> Option<&str> {
1681 use language::ToOffset as _;
1682
1683 let completion = self.active_completion()?;
1684 let excerpt_id = self.excerpt_id?;
1685 let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
1686 if excerpt_id != cursor.excerpt_id
1687 || !completion.range.start.is_valid(completion_buffer)
1688 || !completion.range.end.is_valid(completion_buffer)
1689 {
1690 return None;
1691 }
1692
1693 let mut completion_range = completion.range.to_offset(&completion_buffer);
1694 let prefix_len = Self::common_prefix(
1695 completion_buffer.chars_for_range(completion_range.clone()),
1696 completion.text.chars(),
1697 );
1698 completion_range.start += prefix_len;
1699 let suffix_len = Self::common_prefix(
1700 completion_buffer.reversed_chars_for_range(completion_range.clone()),
1701 completion.text[prefix_len..].chars().rev(),
1702 );
1703 completion_range.end = completion_range.end.saturating_sub(suffix_len);
1704
1705 if completion_range.is_empty()
1706 && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
1707 {
1708 Some(&completion.text[prefix_len..completion.text.len() - suffix_len])
1709 } else {
1710 None
1711 }
1712 }
1713
1714 fn cycle_completions(&mut self, direction: Direction) {
1715 match direction {
1716 Direction::Prev => {
1717 self.active_completion_index = if self.active_completion_index == 0 {
1718 self.completions.len().saturating_sub(1)
1719 } else {
1720 self.active_completion_index - 1
1721 };
1722 }
1723 Direction::Next => {
1724 if self.completions.len() == 0 {
1725 self.active_completion_index = 0
1726 } else {
1727 self.active_completion_index =
1728 (self.active_completion_index + 1) % self.completions.len();
1729 }
1730 }
1731 }
1732 }
1733
1734 fn push_completion(&mut self, new_completion: copilot::Completion) {
1735 for completion in &self.completions {
1736 if completion.text == new_completion.text && completion.range == new_completion.range {
1737 return;
1738 }
1739 }
1740 self.completions.push(new_completion);
1741 }
1742
1743 fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b: T2) -> usize {
1744 a.zip(b)
1745 .take_while(|(a, b)| a == b)
1746 .map(|(a, _)| a.len_utf8())
1747 .sum()
1748 }
1749}
1750
1751#[derive(Debug)]
1752struct ActiveDiagnosticGroup {
1753 primary_range: Range<Anchor>,
1754 primary_message: String,
1755 blocks: HashMap<BlockId, Diagnostic>,
1756 is_valid: bool,
1757}
1758
1759#[derive(Serialize, Deserialize)]
1760pub struct ClipboardSelection {
1761 pub len: usize,
1762 pub is_entire_line: bool,
1763 pub first_line_indent: u32,
1764}
1765
1766#[derive(Debug)]
1767pub struct NavigationData {
1768 cursor_anchor: Anchor,
1769 cursor_position: Point,
1770 scroll_anchor: ScrollAnchor,
1771 scroll_top_row: u32,
1772}
1773
1774pub struct EditorCreated(pub View<Editor>);
1775
1776enum GotoDefinitionKind {
1777 Symbol,
1778 Type,
1779}
1780
1781#[derive(Debug, Clone)]
1782enum InlayHintRefreshReason {
1783 Toggle(bool),
1784 SettingsChange(InlayHintSettings),
1785 NewLinesShown,
1786 BufferEdited(HashSet<Arc<Language>>),
1787 RefreshRequested,
1788 ExcerptsRemoved(Vec<ExcerptId>),
1789}
1790impl InlayHintRefreshReason {
1791 fn description(&self) -> &'static str {
1792 match self {
1793 Self::Toggle(_) => "toggle",
1794 Self::SettingsChange(_) => "settings change",
1795 Self::NewLinesShown => "new lines shown",
1796 Self::BufferEdited(_) => "buffer edited",
1797 Self::RefreshRequested => "refresh requested",
1798 Self::ExcerptsRemoved(_) => "excerpts removed",
1799 }
1800 }
1801}
1802
1803impl Editor {
1804 // pub fn single_line(
1805 // field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1806 // cx: &mut ViewContext<Self>,
1807 // ) -> Self {
1808 // let buffer = cx.build_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
1809 // let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
1810 // Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
1811 // }
1812
1813 // pub fn multi_line(
1814 // field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1815 // cx: &mut ViewContext<Self>,
1816 // ) -> Self {
1817 // let buffer = cx.build_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
1818 // let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
1819 // Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
1820 // }
1821
1822 // pub fn auto_height(
1823 // max_lines: usize,
1824 // field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1825 // cx: &mut ViewContext<Self>,
1826 // ) -> Self {
1827 // let buffer = cx.build_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
1828 // let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
1829 // Self::new(
1830 // EditorMode::AutoHeight { max_lines },
1831 // buffer,
1832 // None,
1833 // field_editor_style,
1834 // cx,
1835 // )
1836 // }
1837
1838 pub fn for_buffer(
1839 buffer: Model<Buffer>,
1840 project: Option<Model<Project>>,
1841 cx: &mut ViewContext<Self>,
1842 ) -> Self {
1843 let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
1844 Self::new(EditorMode::Full, buffer, project, cx)
1845 }
1846
1847 pub fn for_multibuffer(
1848 buffer: Model<MultiBuffer>,
1849 project: Option<Model<Project>>,
1850 cx: &mut ViewContext<Self>,
1851 ) -> Self {
1852 Self::new(EditorMode::Full, buffer, project, cx)
1853 }
1854
1855 pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
1856 let mut clone = Self::new(
1857 self.mode,
1858 self.buffer.clone(),
1859 self.project.clone(),
1860 // todo!
1861 // self.get_field_editor_theme.clone(),
1862 cx,
1863 );
1864 self.display_map.update(cx, |display_map, cx| {
1865 let snapshot = display_map.snapshot(cx);
1866 clone.display_map.update(cx, |display_map, cx| {
1867 display_map.set_state(&snapshot, cx);
1868 });
1869 });
1870 clone.selections.clone_state(&self.selections);
1871 clone.scroll_manager.clone_state(&self.scroll_manager);
1872 clone.searchable = self.searchable;
1873 clone
1874 }
1875
1876 fn new(
1877 mode: EditorMode,
1878 buffer: Model<MultiBuffer>,
1879 project: Option<Model<Project>>,
1880 // todo!()
1881 // get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
1882 cx: &mut ViewContext<Self>,
1883 ) -> Self {
1884 // let editor_view_id = cx.view_id();
1885 let style = cx.text_style();
1886 let font_size = style.font_size * cx.rem_size();
1887 let display_map = cx.build_model(|cx| {
1888 // todo!()
1889 // let settings = settings::get::<ThemeSettings>(cx);
1890 // let style = build_style(settings, get_field_editor_theme.as_deref(), None, cx);
1891 DisplayMap::new(buffer.clone(), style.font(), font_size, None, 2, 1, cx)
1892 });
1893
1894 let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
1895
1896 let blink_manager = cx.build_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
1897
1898 let soft_wrap_mode_override =
1899 (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
1900
1901 let mut project_subscriptions = Vec::new();
1902 if mode == EditorMode::Full {
1903 if let Some(project) = project.as_ref() {
1904 if buffer.read(cx).is_singleton() {
1905 project_subscriptions.push(cx.observe(project, |_, _, cx| {
1906 cx.emit(Event::TitleChanged);
1907 }));
1908 }
1909 project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
1910 if let project::Event::RefreshInlayHints = event {
1911 editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
1912 };
1913 }));
1914 }
1915 }
1916
1917 let inlay_hint_settings = inlay_hint_settings(
1918 selections.newest_anchor().head(),
1919 &buffer.read(cx).snapshot(cx),
1920 cx,
1921 );
1922
1923 let mut this = Self {
1924 handle: cx.view().downgrade(),
1925 focus_handle: cx.focus_handle(),
1926 buffer: buffer.clone(),
1927 display_map: display_map.clone(),
1928 selections,
1929 scroll_manager: ScrollManager::new(),
1930 columnar_selection_tail: None,
1931 add_selections_state: None,
1932 select_next_state: None,
1933 select_prev_state: None,
1934 selection_history: Default::default(),
1935 autoclose_regions: Default::default(),
1936 snippet_stack: Default::default(),
1937 select_larger_syntax_node_stack: Vec::new(),
1938 ime_transaction: Default::default(),
1939 active_diagnostics: None,
1940 soft_wrap_mode_override,
1941 // get_field_editor_theme,
1942 collaboration_hub: project.clone().map(|project| Box::new(project) as _),
1943 project,
1944 focused: false,
1945 blink_manager: blink_manager.clone(),
1946 show_local_selections: true,
1947 mode,
1948 show_gutter: mode == EditorMode::Full,
1949 show_wrap_guides: None,
1950 placeholder_text: None,
1951 highlighted_rows: None,
1952 background_highlights: Default::default(),
1953 inlay_background_highlights: Default::default(),
1954 nav_history: None,
1955 context_menu: RwLock::new(None),
1956 // mouse_context_menu: cx
1957 // .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)),
1958 completion_tasks: Default::default(),
1959 next_completion_id: 0,
1960 next_inlay_id: 0,
1961 available_code_actions: Default::default(),
1962 code_actions_task: Default::default(),
1963 document_highlights_task: Default::default(),
1964 pending_rename: Default::default(),
1965 searchable: true,
1966 // override_text_style: None,
1967 cursor_shape: Default::default(),
1968 autoindent_mode: Some(AutoindentMode::EachLine),
1969 collapse_matches: false,
1970 workspace: None,
1971 // keymap_context_layers: Default::default(),
1972 input_enabled: true,
1973 read_only: false,
1974 leader_peer_id: None,
1975 remote_id: None,
1976 hover_state: Default::default(),
1977 link_go_to_definition_state: Default::default(),
1978 copilot_state: Default::default(),
1979 inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
1980 gutter_hovered: false,
1981 pixel_position_of_newest_cursor: None,
1982 _subscriptions: vec![
1983 cx.observe(&buffer, Self::on_buffer_changed),
1984 cx.subscribe(&buffer, Self::on_buffer_event),
1985 cx.observe(&display_map, Self::on_display_map_changed),
1986 cx.observe(&blink_manager, |_, _, cx| cx.notify()),
1987 cx.observe_global::<SettingsStore>(Self::settings_changed),
1988 cx.observe_window_activation(|editor, cx| {
1989 let active = cx.is_window_active();
1990 editor.blink_manager.update(cx, |blink_manager, cx| {
1991 if active {
1992 blink_manager.enable(cx);
1993 } else {
1994 blink_manager.show_cursor(cx);
1995 blink_manager.disable(cx);
1996 }
1997 });
1998 }),
1999 ],
2000 };
2001
2002 this._subscriptions.extend(project_subscriptions);
2003
2004 this.end_selection(cx);
2005 this.scroll_manager.show_scrollbar(cx);
2006
2007 // todo!("use a different mechanism")
2008 // let editor_created_event = EditorCreated(cx.handle());
2009 // cx.emit_global(editor_created_event);
2010
2011 if mode == EditorMode::Full {
2012 let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
2013 cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
2014 }
2015
2016 this.report_editor_event("open", None, cx);
2017 this
2018 }
2019
2020 // pub fn new_file(
2021 // workspace: &mut Workspace,
2022 // _: &workspace::NewFile,
2023 // cx: &mut ViewContext<Workspace>,
2024 // ) {
2025 // let project = workspace.project().clone();
2026 // if project.read(cx).is_remote() {
2027 // cx.propagate_action();
2028 // } else if let Some(buffer) = project
2029 // .update(cx, |project, cx| project.create_buffer("", None, cx))
2030 // .log_err()
2031 // {
2032 // workspace.add_item(
2033 // Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
2034 // cx,
2035 // );
2036 // }
2037 // }
2038
2039 // pub fn new_file_in_direction(
2040 // workspace: &mut Workspace,
2041 // action: &workspace::NewFileInDirection,
2042 // cx: &mut ViewContext<Workspace>,
2043 // ) {
2044 // let project = workspace.project().clone();
2045 // if project.read(cx).is_remote() {
2046 // cx.propagate_action();
2047 // } else if let Some(buffer) = project
2048 // .update(cx, |project, cx| project.create_buffer("", None, cx))
2049 // .log_err()
2050 // {
2051 // workspace.split_item(
2052 // action.0,
2053 // Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
2054 // cx,
2055 // );
2056 // }
2057 // }
2058
2059 pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
2060 self.buffer.read(cx).replica_id()
2061 }
2062
2063 // pub fn leader_peer_id(&self) -> Option<PeerId> {
2064 // self.leader_peer_id
2065 // }
2066
2067 pub fn buffer(&self) -> &Model<MultiBuffer> {
2068 &self.buffer
2069 }
2070
2071 fn workspace(&self) -> Option<View<Workspace>> {
2072 self.workspace.as_ref()?.0.upgrade()
2073 }
2074
2075 pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
2076 self.buffer().read(cx).title(cx)
2077 }
2078
2079 pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
2080 EditorSnapshot {
2081 mode: self.mode,
2082 show_gutter: self.show_gutter,
2083 display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
2084 scroll_anchor: self.scroll_manager.anchor(),
2085 ongoing_scroll: self.scroll_manager.ongoing_scroll(),
2086 placeholder_text: self.placeholder_text.clone(),
2087 is_focused: self.focus_handle.is_focused(cx),
2088 }
2089 }
2090
2091 // pub fn language_at<'a, T: ToOffset>(
2092 // &self,
2093 // point: T,
2094 // cx: &'a AppContext,
2095 // ) -> Option<Arc<Language>> {
2096 // self.buffer.read(cx).language_at(point, cx)
2097 // }
2098
2099 // pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option<Arc<dyn File>> {
2100 // self.buffer.read(cx).read(cx).file_at(point).cloned()
2101 // }
2102
2103 // pub fn active_excerpt(
2104 // &self,
2105 // cx: &AppContext,
2106 // ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
2107 // self.buffer
2108 // .read(cx)
2109 // .excerpt_containing(self.selections.newest_anchor().head(), cx)
2110 // }
2111
2112 // pub fn style(&self, cx: &AppContext) -> EditorStyle {
2113 // build_style(
2114 // settings::get::<ThemeSettings>(cx),
2115 // self.get_field_editor_theme.as_deref(),
2116 // self.override_text_style.as_deref(),
2117 // cx,
2118 // )
2119 // }
2120
2121 // pub fn mode(&self) -> EditorMode {
2122 // self.mode
2123 // }
2124
2125 // pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
2126 // self.collaboration_hub.as_deref()
2127 // }
2128
2129 // pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
2130 // self.collaboration_hub = Some(hub);
2131 // }
2132
2133 // pub fn set_placeholder_text(
2134 // &mut self,
2135 // placeholder_text: impl Into<Arc<str>>,
2136 // cx: &mut ViewContext<Self>,
2137 // ) {
2138 // self.placeholder_text = Some(placeholder_text.into());
2139 // cx.notify();
2140 // }
2141
2142 // pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
2143 // self.cursor_shape = cursor_shape;
2144 // cx.notify();
2145 // }
2146
2147 // pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
2148 // self.collapse_matches = collapse_matches;
2149 // }
2150
2151 pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
2152 if self.collapse_matches {
2153 return range.start..range.start;
2154 }
2155 range.clone()
2156 }
2157
2158 // pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
2159 // if self.display_map.read(cx).clip_at_line_ends != clip {
2160 // self.display_map
2161 // .update(cx, |map, _| map.clip_at_line_ends = clip);
2162 // }
2163 // }
2164
2165 // pub fn set_keymap_context_layer<Tag: 'static>(
2166 // &mut self,
2167 // context: KeymapContext,
2168 // cx: &mut ViewContext<Self>,
2169 // ) {
2170 // self.keymap_context_layers
2171 // .insert(TypeId::of::<Tag>(), context);
2172 // cx.notify();
2173 // }
2174
2175 // pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
2176 // self.keymap_context_layers.remove(&TypeId::of::<Tag>());
2177 // cx.notify();
2178 // }
2179
2180 // pub fn set_input_enabled(&mut self, input_enabled: bool) {
2181 // self.input_enabled = input_enabled;
2182 // }
2183
2184 // pub fn set_autoindent(&mut self, autoindent: bool) {
2185 // if autoindent {
2186 // self.autoindent_mode = Some(AutoindentMode::EachLine);
2187 // } else {
2188 // self.autoindent_mode = None;
2189 // }
2190 // }
2191
2192 // pub fn read_only(&self) -> bool {
2193 // self.read_only
2194 // }
2195
2196 // pub fn set_read_only(&mut self, read_only: bool) {
2197 // self.read_only = read_only;
2198 // }
2199
2200 // pub fn set_field_editor_style(
2201 // &mut self,
2202 // style: Option<Arc<GetFieldEditorTheme>>,
2203 // cx: &mut ViewContext<Self>,
2204 // ) {
2205 // self.get_field_editor_theme = style;
2206 // cx.notify();
2207 // }
2208
2209 fn selections_did_change(
2210 &mut self,
2211 local: bool,
2212 old_cursor_position: &Anchor,
2213 cx: &mut ViewContext<Self>,
2214 ) {
2215 if self.focused && self.leader_peer_id.is_none() {
2216 self.buffer.update(cx, |buffer, cx| {
2217 buffer.set_active_selections(
2218 &self.selections.disjoint_anchors(),
2219 self.selections.line_mode,
2220 self.cursor_shape,
2221 cx,
2222 )
2223 });
2224 }
2225
2226 let display_map = self
2227 .display_map
2228 .update(cx, |display_map, cx| display_map.snapshot(cx));
2229 let buffer = &display_map.buffer_snapshot;
2230 self.add_selections_state = None;
2231 self.select_next_state = None;
2232 self.select_prev_state = None;
2233 self.select_larger_syntax_node_stack.clear();
2234 self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
2235 self.snippet_stack
2236 .invalidate(&self.selections.disjoint_anchors(), buffer);
2237 self.take_rename(false, cx);
2238
2239 let new_cursor_position = self.selections.newest_anchor().head();
2240
2241 self.push_to_nav_history(
2242 old_cursor_position.clone(),
2243 Some(new_cursor_position.to_point(buffer)),
2244 cx,
2245 );
2246
2247 if local {
2248 let new_cursor_position = self.selections.newest_anchor().head();
2249 let mut context_menu = self.context_menu.write();
2250 let completion_menu = match context_menu.as_ref() {
2251 Some(ContextMenu::Completions(menu)) => Some(menu),
2252
2253 _ => {
2254 *context_menu = None;
2255 None
2256 }
2257 };
2258
2259 if let Some(completion_menu) = completion_menu {
2260 let cursor_position = new_cursor_position.to_offset(buffer);
2261 let (word_range, kind) =
2262 buffer.surrounding_word(completion_menu.initial_position.clone());
2263 if kind == Some(CharKind::Word)
2264 && word_range.to_inclusive().contains(&cursor_position)
2265 {
2266 let mut completion_menu = completion_menu.clone();
2267 drop(context_menu);
2268
2269 let query = Self::completion_query(buffer, cursor_position);
2270 cx.spawn(move |this, mut cx| async move {
2271 completion_menu
2272 .filter(query.as_deref(), cx.background_executor().clone())
2273 .await;
2274
2275 this.update(&mut cx, |this, cx| {
2276 let mut context_menu = this.context_menu.write();
2277 let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
2278 return;
2279 };
2280
2281 if menu.id > completion_menu.id {
2282 return;
2283 }
2284
2285 *context_menu = Some(ContextMenu::Completions(completion_menu));
2286 drop(context_menu);
2287 cx.notify();
2288 })
2289 })
2290 .detach();
2291
2292 self.show_completions(&ShowCompletions, cx);
2293 } else {
2294 drop(context_menu);
2295 self.hide_context_menu(cx);
2296 }
2297 } else {
2298 drop(context_menu);
2299 }
2300
2301 hide_hover(self, cx);
2302
2303 if old_cursor_position.to_display_point(&display_map).row()
2304 != new_cursor_position.to_display_point(&display_map).row()
2305 {
2306 self.available_code_actions.take();
2307 }
2308 self.refresh_code_actions(cx);
2309 self.refresh_document_highlights(cx);
2310 refresh_matching_bracket_highlights(self, cx);
2311 self.discard_copilot_suggestion(cx);
2312 }
2313
2314 self.blink_manager.update(cx, BlinkManager::pause_blinking);
2315 cx.emit(Event::SelectionsChanged { local });
2316 cx.notify();
2317 }
2318
2319 pub fn change_selections<R>(
2320 &mut self,
2321 autoscroll: Option<Autoscroll>,
2322 cx: &mut ViewContext<Self>,
2323 change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
2324 ) -> R {
2325 let old_cursor_position = self.selections.newest_anchor().head();
2326 self.push_to_selection_history();
2327
2328 let (changed, result) = self.selections.change_with(cx, change);
2329
2330 if changed {
2331 if let Some(autoscroll) = autoscroll {
2332 self.request_autoscroll(autoscroll, cx);
2333 }
2334 self.selections_did_change(true, &old_cursor_position, cx);
2335 }
2336
2337 result
2338 }
2339
2340 pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
2341 where
2342 I: IntoIterator<Item = (Range<S>, T)>,
2343 S: ToOffset,
2344 T: Into<Arc<str>>,
2345 {
2346 if self.read_only {
2347 return;
2348 }
2349
2350 self.buffer
2351 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
2352 }
2353
2354 // pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
2355 // where
2356 // I: IntoIterator<Item = (Range<S>, T)>,
2357 // S: ToOffset,
2358 // T: Into<Arc<str>>,
2359 // {
2360 // if self.read_only {
2361 // return;
2362 // }
2363
2364 // self.buffer.update(cx, |buffer, cx| {
2365 // buffer.edit(edits, self.autoindent_mode.clone(), cx)
2366 // });
2367 // }
2368
2369 // pub fn edit_with_block_indent<I, S, T>(
2370 // &mut self,
2371 // edits: I,
2372 // original_indent_columns: Vec<u32>,
2373 // cx: &mut ViewContext<Self>,
2374 // ) where
2375 // I: IntoIterator<Item = (Range<S>, T)>,
2376 // S: ToOffset,
2377 // T: Into<Arc<str>>,
2378 // {
2379 // if self.read_only {
2380 // return;
2381 // }
2382
2383 // self.buffer.update(cx, |buffer, cx| {
2384 // buffer.edit(
2385 // edits,
2386 // Some(AutoindentMode::Block {
2387 // original_indent_columns,
2388 // }),
2389 // cx,
2390 // )
2391 // });
2392 // }
2393
2394 fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
2395 self.hide_context_menu(cx);
2396
2397 match phase {
2398 SelectPhase::Begin {
2399 position,
2400 add,
2401 click_count,
2402 } => self.begin_selection(position, add, click_count, cx),
2403 SelectPhase::BeginColumnar {
2404 position,
2405 goal_column,
2406 } => self.begin_columnar_selection(position, goal_column, cx),
2407 SelectPhase::Extend {
2408 position,
2409 click_count,
2410 } => self.extend_selection(position, click_count, cx),
2411 SelectPhase::Update {
2412 position,
2413 goal_column,
2414 scroll_position,
2415 } => self.update_selection(position, goal_column, scroll_position, cx),
2416 SelectPhase::End => self.end_selection(cx),
2417 }
2418 }
2419
2420 fn extend_selection(
2421 &mut self,
2422 position: DisplayPoint,
2423 click_count: usize,
2424 cx: &mut ViewContext<Self>,
2425 ) {
2426 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2427 let tail = self.selections.newest::<usize>(cx).tail();
2428 self.begin_selection(position, false, click_count, cx);
2429
2430 let position = position.to_offset(&display_map, Bias::Left);
2431 let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
2432
2433 let mut pending_selection = self
2434 .selections
2435 .pending_anchor()
2436 .expect("extend_selection not called with pending selection");
2437 if position >= tail {
2438 pending_selection.start = tail_anchor;
2439 } else {
2440 pending_selection.end = tail_anchor;
2441 pending_selection.reversed = true;
2442 }
2443
2444 let mut pending_mode = self.selections.pending_mode().unwrap();
2445 match &mut pending_mode {
2446 SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
2447 _ => {}
2448 }
2449
2450 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2451 s.set_pending(pending_selection, pending_mode)
2452 });
2453 }
2454
2455 fn begin_selection(
2456 &mut self,
2457 position: DisplayPoint,
2458 add: bool,
2459 click_count: usize,
2460 cx: &mut ViewContext<Self>,
2461 ) {
2462 if !self.focused {
2463 cx.focus(&self.focus_handle);
2464 }
2465
2466 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2467 let buffer = &display_map.buffer_snapshot;
2468 let newest_selection = self.selections.newest_anchor().clone();
2469 let position = display_map.clip_point(position, Bias::Left);
2470
2471 let start;
2472 let end;
2473 let mode;
2474 let auto_scroll;
2475 match click_count {
2476 1 => {
2477 start = buffer.anchor_before(position.to_point(&display_map));
2478 end = start.clone();
2479 mode = SelectMode::Character;
2480 auto_scroll = true;
2481 }
2482 2 => {
2483 let range = movement::surrounding_word(&display_map, position);
2484 start = buffer.anchor_before(range.start.to_point(&display_map));
2485 end = buffer.anchor_before(range.end.to_point(&display_map));
2486 mode = SelectMode::Word(start.clone()..end.clone());
2487 auto_scroll = true;
2488 }
2489 3 => {
2490 let position = display_map
2491 .clip_point(position, Bias::Left)
2492 .to_point(&display_map);
2493 let line_start = display_map.prev_line_boundary(position).0;
2494 let next_line_start = buffer.clip_point(
2495 display_map.next_line_boundary(position).0 + Point::new(1, 0),
2496 Bias::Left,
2497 );
2498 start = buffer.anchor_before(line_start);
2499 end = buffer.anchor_before(next_line_start);
2500 mode = SelectMode::Line(start.clone()..end.clone());
2501 auto_scroll = true;
2502 }
2503 _ => {
2504 start = buffer.anchor_before(0);
2505 end = buffer.anchor_before(buffer.len());
2506 mode = SelectMode::All;
2507 auto_scroll = false;
2508 }
2509 }
2510
2511 self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
2512 if !add {
2513 s.clear_disjoint();
2514 } else if click_count > 1 {
2515 s.delete(newest_selection.id)
2516 }
2517
2518 s.set_pending_anchor_range(start..end, mode);
2519 });
2520 }
2521
2522 fn begin_columnar_selection(
2523 &mut self,
2524 position: DisplayPoint,
2525 goal_column: u32,
2526 cx: &mut ViewContext<Self>,
2527 ) {
2528 if !self.focused {
2529 cx.focus(&self.focus_handle);
2530 }
2531
2532 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2533 let tail = self.selections.newest::<Point>(cx).tail();
2534 self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
2535
2536 self.select_columns(
2537 tail.to_display_point(&display_map),
2538 position,
2539 goal_column,
2540 &display_map,
2541 cx,
2542 );
2543 }
2544
2545 fn update_selection(
2546 &mut self,
2547 position: DisplayPoint,
2548 goal_column: u32,
2549 scroll_position: gpui::Point<f32>,
2550 cx: &mut ViewContext<Self>,
2551 ) {
2552 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2553
2554 if let Some(tail) = self.columnar_selection_tail.as_ref() {
2555 let tail = tail.to_display_point(&display_map);
2556 self.select_columns(tail, position, goal_column, &display_map, cx);
2557 } else if let Some(mut pending) = self.selections.pending_anchor() {
2558 let buffer = self.buffer.read(cx).snapshot(cx);
2559 let head;
2560 let tail;
2561 let mode = self.selections.pending_mode().unwrap();
2562 match &mode {
2563 SelectMode::Character => {
2564 head = position.to_point(&display_map);
2565 tail = pending.tail().to_point(&buffer);
2566 }
2567 SelectMode::Word(original_range) => {
2568 let original_display_range = original_range.start.to_display_point(&display_map)
2569 ..original_range.end.to_display_point(&display_map);
2570 let original_buffer_range = original_display_range.start.to_point(&display_map)
2571 ..original_display_range.end.to_point(&display_map);
2572 if movement::is_inside_word(&display_map, position)
2573 || original_display_range.contains(&position)
2574 {
2575 let word_range = movement::surrounding_word(&display_map, position);
2576 if word_range.start < original_display_range.start {
2577 head = word_range.start.to_point(&display_map);
2578 } else {
2579 head = word_range.end.to_point(&display_map);
2580 }
2581 } else {
2582 head = position.to_point(&display_map);
2583 }
2584
2585 if head <= original_buffer_range.start {
2586 tail = original_buffer_range.end;
2587 } else {
2588 tail = original_buffer_range.start;
2589 }
2590 }
2591 SelectMode::Line(original_range) => {
2592 let original_range = original_range.to_point(&display_map.buffer_snapshot);
2593
2594 let position = display_map
2595 .clip_point(position, Bias::Left)
2596 .to_point(&display_map);
2597 let line_start = display_map.prev_line_boundary(position).0;
2598 let next_line_start = buffer.clip_point(
2599 display_map.next_line_boundary(position).0 + Point::new(1, 0),
2600 Bias::Left,
2601 );
2602
2603 if line_start < original_range.start {
2604 head = line_start
2605 } else {
2606 head = next_line_start
2607 }
2608
2609 if head <= original_range.start {
2610 tail = original_range.end;
2611 } else {
2612 tail = original_range.start;
2613 }
2614 }
2615 SelectMode::All => {
2616 return;
2617 }
2618 };
2619
2620 if head < tail {
2621 pending.start = buffer.anchor_before(head);
2622 pending.end = buffer.anchor_before(tail);
2623 pending.reversed = true;
2624 } else {
2625 pending.start = buffer.anchor_before(tail);
2626 pending.end = buffer.anchor_before(head);
2627 pending.reversed = false;
2628 }
2629
2630 self.change_selections(None, cx, |s| {
2631 s.set_pending(pending, mode);
2632 });
2633 } else {
2634 log::error!("update_selection dispatched with no pending selection");
2635 return;
2636 }
2637
2638 self.set_scroll_position(scroll_position, cx);
2639 cx.notify();
2640 }
2641
2642 fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
2643 self.columnar_selection_tail.take();
2644 if self.selections.pending_anchor().is_some() {
2645 let selections = self.selections.all::<usize>(cx);
2646 self.change_selections(None, cx, |s| {
2647 s.select(selections);
2648 s.clear_pending();
2649 });
2650 }
2651 }
2652
2653 fn select_columns(
2654 &mut self,
2655 tail: DisplayPoint,
2656 head: DisplayPoint,
2657 goal_column: u32,
2658 display_map: &DisplaySnapshot,
2659 cx: &mut ViewContext<Self>,
2660 ) {
2661 let start_row = cmp::min(tail.row(), head.row());
2662 let end_row = cmp::max(tail.row(), head.row());
2663 let start_column = cmp::min(tail.column(), goal_column);
2664 let end_column = cmp::max(tail.column(), goal_column);
2665 let reversed = start_column < tail.column();
2666
2667 let selection_ranges = (start_row..=end_row)
2668 .filter_map(|row| {
2669 if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
2670 let start = display_map
2671 .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
2672 .to_point(display_map);
2673 let end = display_map
2674 .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
2675 .to_point(display_map);
2676 if reversed {
2677 Some(end..start)
2678 } else {
2679 Some(start..end)
2680 }
2681 } else {
2682 None
2683 }
2684 })
2685 .collect::<Vec<_>>();
2686
2687 self.change_selections(None, cx, |s| {
2688 s.select_ranges(selection_ranges);
2689 });
2690 cx.notify();
2691 }
2692
2693 pub fn has_pending_nonempty_selection(&self) -> bool {
2694 let pending_nonempty_selection = match self.selections.pending_anchor() {
2695 Some(Selection { start, end, .. }) => start != end,
2696 None => false,
2697 };
2698 pending_nonempty_selection || self.columnar_selection_tail.is_some()
2699 }
2700
2701 pub fn has_pending_selection(&self) -> bool {
2702 self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
2703 }
2704
2705 // pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
2706 // if self.take_rename(false, cx).is_some() {
2707 // return;
2708 // }
2709
2710 // if hide_hover(self, cx) {
2711 // return;
2712 // }
2713
2714 // if self.hide_context_menu(cx).is_some() {
2715 // return;
2716 // }
2717
2718 // if self.discard_copilot_suggestion(cx) {
2719 // return;
2720 // }
2721
2722 // if self.snippet_stack.pop().is_some() {
2723 // return;
2724 // }
2725
2726 // if self.mode == EditorMode::Full {
2727 // if self.active_diagnostics.is_some() {
2728 // self.dismiss_diagnostics(cx);
2729 // return;
2730 // }
2731
2732 // if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
2733 // return;
2734 // }
2735 // }
2736
2737 // cx.propagate_action();
2738 // }
2739
2740 // pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2741 // let text: Arc<str> = text.into();
2742
2743 // if self.read_only {
2744 // return;
2745 // }
2746
2747 // let selections = self.selections.all_adjusted(cx);
2748 // let mut brace_inserted = false;
2749 // let mut edits = Vec::new();
2750 // let mut new_selections = Vec::with_capacity(selections.len());
2751 // let mut new_autoclose_regions = Vec::new();
2752 // let snapshot = self.buffer.read(cx).read(cx);
2753
2754 // for (selection, autoclose_region) in
2755 // self.selections_with_autoclose_regions(selections, &snapshot)
2756 // {
2757 // if let Some(scope) = snapshot.language_scope_at(selection.head()) {
2758 // // Determine if the inserted text matches the opening or closing
2759 // // bracket of any of this language's bracket pairs.
2760 // let mut bracket_pair = None;
2761 // let mut is_bracket_pair_start = false;
2762 // if !text.is_empty() {
2763 // // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified)
2764 // // and they are removing the character that triggered IME popup.
2765 // for (pair, enabled) in scope.brackets() {
2766 // if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
2767 // bracket_pair = Some(pair.clone());
2768 // is_bracket_pair_start = true;
2769 // break;
2770 // } else if pair.end.as_str() == text.as_ref() {
2771 // bracket_pair = Some(pair.clone());
2772 // break;
2773 // }
2774 // }
2775 // }
2776
2777 // if let Some(bracket_pair) = bracket_pair {
2778 // if selection.is_empty() {
2779 // if is_bracket_pair_start {
2780 // let prefix_len = bracket_pair.start.len() - text.len();
2781
2782 // // If the inserted text is a suffix of an opening bracket and the
2783 // // selection is preceded by the rest of the opening bracket, then
2784 // // insert the closing bracket.
2785 // let following_text_allows_autoclose = snapshot
2786 // .chars_at(selection.start)
2787 // .next()
2788 // .map_or(true, |c| scope.should_autoclose_before(c));
2789 // let preceding_text_matches_prefix = prefix_len == 0
2790 // || (selection.start.column >= (prefix_len as u32)
2791 // && snapshot.contains_str_at(
2792 // Point::new(
2793 // selection.start.row,
2794 // selection.start.column - (prefix_len as u32),
2795 // ),
2796 // &bracket_pair.start[..prefix_len],
2797 // ));
2798 // if following_text_allows_autoclose && preceding_text_matches_prefix {
2799 // let anchor = snapshot.anchor_before(selection.end);
2800 // new_selections.push((selection.map(|_| anchor), text.len()));
2801 // new_autoclose_regions.push((
2802 // anchor,
2803 // text.len(),
2804 // selection.id,
2805 // bracket_pair.clone(),
2806 // ));
2807 // edits.push((
2808 // selection.range(),
2809 // format!("{}{}", text, bracket_pair.end).into(),
2810 // ));
2811 // brace_inserted = true;
2812 // continue;
2813 // }
2814 // }
2815
2816 // if let Some(region) = autoclose_region {
2817 // // If the selection is followed by an auto-inserted closing bracket,
2818 // // then don't insert that closing bracket again; just move the selection
2819 // // past the closing bracket.
2820 // let should_skip = selection.end == region.range.end.to_point(&snapshot)
2821 // && text.as_ref() == region.pair.end.as_str();
2822 // if should_skip {
2823 // let anchor = snapshot.anchor_after(selection.end);
2824 // new_selections
2825 // .push((selection.map(|_| anchor), region.pair.end.len()));
2826 // continue;
2827 // }
2828 // }
2829 // }
2830 // // If an opening bracket is 1 character long and is typed while
2831 // // text is selected, then surround that text with the bracket pair.
2832 // else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
2833 // edits.push((selection.start..selection.start, text.clone()));
2834 // edits.push((
2835 // selection.end..selection.end,
2836 // bracket_pair.end.as_str().into(),
2837 // ));
2838 // brace_inserted = true;
2839 // new_selections.push((
2840 // Selection {
2841 // id: selection.id,
2842 // start: snapshot.anchor_after(selection.start),
2843 // end: snapshot.anchor_before(selection.end),
2844 // reversed: selection.reversed,
2845 // goal: selection.goal,
2846 // },
2847 // 0,
2848 // ));
2849 // continue;
2850 // }
2851 // }
2852 // }
2853
2854 // // If not handling any auto-close operation, then just replace the selected
2855 // // text with the given input and move the selection to the end of the
2856 // // newly inserted text.
2857 // let anchor = snapshot.anchor_after(selection.end);
2858 // new_selections.push((selection.map(|_| anchor), 0));
2859 // edits.push((selection.start..selection.end, text.clone()));
2860 // }
2861
2862 // drop(snapshot);
2863 // self.transact(cx, |this, cx| {
2864 // this.buffer.update(cx, |buffer, cx| {
2865 // buffer.edit(edits, this.autoindent_mode.clone(), cx);
2866 // });
2867
2868 // let new_anchor_selections = new_selections.iter().map(|e| &e.0);
2869 // let new_selection_deltas = new_selections.iter().map(|e| e.1);
2870 // let snapshot = this.buffer.read(cx).read(cx);
2871 // let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
2872 // .zip(new_selection_deltas)
2873 // .map(|(selection, delta)| Selection {
2874 // id: selection.id,
2875 // start: selection.start + delta,
2876 // end: selection.end + delta,
2877 // reversed: selection.reversed,
2878 // goal: SelectionGoal::None,
2879 // })
2880 // .collect::<Vec<_>>();
2881
2882 // let mut i = 0;
2883 // for (position, delta, selection_id, pair) in new_autoclose_regions {
2884 // let position = position.to_offset(&snapshot) + delta;
2885 // let start = snapshot.anchor_before(position);
2886 // let end = snapshot.anchor_after(position);
2887 // while let Some(existing_state) = this.autoclose_regions.get(i) {
2888 // match existing_state.range.start.cmp(&start, &snapshot) {
2889 // Ordering::Less => i += 1,
2890 // Ordering::Greater => break,
2891 // Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
2892 // Ordering::Less => i += 1,
2893 // Ordering::Equal => break,
2894 // Ordering::Greater => break,
2895 // },
2896 // }
2897 // }
2898 // this.autoclose_regions.insert(
2899 // i,
2900 // AutocloseRegion {
2901 // selection_id,
2902 // range: start..end,
2903 // pair,
2904 // },
2905 // );
2906 // }
2907
2908 // drop(snapshot);
2909 // let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
2910 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2911
2912 // if !brace_inserted && EditorSettings>(cx).use_on_type_format {
2913 // if let Some(on_type_format_task) =
2914 // this.trigger_on_type_formatting(text.to_string(), cx)
2915 // {
2916 // on_type_format_task.detach_and_log_err(cx);
2917 // }
2918 // }
2919
2920 // if had_active_copilot_suggestion {
2921 // this.refresh_copilot_suggestions(true, cx);
2922 // if !this.has_active_copilot_suggestion(cx) {
2923 // this.trigger_completion_on_input(&text, cx);
2924 // }
2925 // } else {
2926 // this.trigger_completion_on_input(&text, cx);
2927 // this.refresh_copilot_suggestions(true, cx);
2928 // }
2929 // });
2930 // }
2931
2932 // pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
2933 // self.transact(cx, |this, cx| {
2934 // let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
2935 // let selections = this.selections.all::<usize>(cx);
2936 // let multi_buffer = this.buffer.read(cx);
2937 // let buffer = multi_buffer.snapshot(cx);
2938 // selections
2939 // .iter()
2940 // .map(|selection| {
2941 // let start_point = selection.start.to_point(&buffer);
2942 // let mut indent = buffer.indent_size_for_line(start_point.row);
2943 // indent.len = cmp::min(indent.len, start_point.column);
2944 // let start = selection.start;
2945 // let end = selection.end;
2946 // let is_cursor = start == end;
2947 // let language_scope = buffer.language_scope_at(start);
2948 // let (comment_delimiter, insert_extra_newline) = if let Some(language) =
2949 // &language_scope
2950 // {
2951 // let leading_whitespace_len = buffer
2952 // .reversed_chars_at(start)
2953 // .take_while(|c| c.is_whitespace() && *c != '\n')
2954 // .map(|c| c.len_utf8())
2955 // .sum::<usize>();
2956
2957 // let trailing_whitespace_len = buffer
2958 // .chars_at(end)
2959 // .take_while(|c| c.is_whitespace() && *c != '\n')
2960 // .map(|c| c.len_utf8())
2961 // .sum::<usize>();
2962
2963 // let insert_extra_newline =
2964 // language.brackets().any(|(pair, enabled)| {
2965 // let pair_start = pair.start.trim_end();
2966 // let pair_end = pair.end.trim_start();
2967
2968 // enabled
2969 // && pair.newline
2970 // && buffer.contains_str_at(
2971 // end + trailing_whitespace_len,
2972 // pair_end,
2973 // )
2974 // && buffer.contains_str_at(
2975 // (start - leading_whitespace_len)
2976 // .saturating_sub(pair_start.len()),
2977 // pair_start,
2978 // )
2979 // });
2980 // // Comment extension on newline is allowed only for cursor selections
2981 // let comment_delimiter = language.line_comment_prefix().filter(|_| {
2982 // let is_comment_extension_enabled =
2983 // multi_buffer.settings_at(0, cx).extend_comment_on_newline;
2984 // is_cursor && is_comment_extension_enabled
2985 // });
2986 // let comment_delimiter = if let Some(delimiter) = comment_delimiter {
2987 // buffer
2988 // .buffer_line_for_row(start_point.row)
2989 // .is_some_and(|(snapshot, range)| {
2990 // let mut index_of_first_non_whitespace = 0;
2991 // let line_starts_with_comment = snapshot
2992 // .chars_for_range(range)
2993 // .skip_while(|c| {
2994 // let should_skip = c.is_whitespace();
2995 // if should_skip {
2996 // index_of_first_non_whitespace += 1;
2997 // }
2998 // should_skip
2999 // })
3000 // .take(delimiter.len())
3001 // .eq(delimiter.chars());
3002 // let cursor_is_placed_after_comment_marker =
3003 // index_of_first_non_whitespace + delimiter.len()
3004 // <= start_point.column as usize;
3005 // line_starts_with_comment
3006 // && cursor_is_placed_after_comment_marker
3007 // })
3008 // .then(|| delimiter.clone())
3009 // } else {
3010 // None
3011 // };
3012 // (comment_delimiter, insert_extra_newline)
3013 // } else {
3014 // (None, false)
3015 // };
3016
3017 // let capacity_for_delimiter = comment_delimiter
3018 // .as_deref()
3019 // .map(str::len)
3020 // .unwrap_or_default();
3021 // let mut new_text =
3022 // String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
3023 // new_text.push_str("\n");
3024 // new_text.extend(indent.chars());
3025 // if let Some(delimiter) = &comment_delimiter {
3026 // new_text.push_str(&delimiter);
3027 // }
3028 // if insert_extra_newline {
3029 // new_text = new_text.repeat(2);
3030 // }
3031
3032 // let anchor = buffer.anchor_after(end);
3033 // let new_selection = selection.map(|_| anchor);
3034 // (
3035 // (start..end, new_text),
3036 // (insert_extra_newline, new_selection),
3037 // )
3038 // })
3039 // .unzip()
3040 // };
3041
3042 // this.edit_with_autoindent(edits, cx);
3043 // let buffer = this.buffer.read(cx).snapshot(cx);
3044 // let new_selections = selection_fixup_info
3045 // .into_iter()
3046 // .map(|(extra_newline_inserted, new_selection)| {
3047 // let mut cursor = new_selection.end.to_point(&buffer);
3048 // if extra_newline_inserted {
3049 // cursor.row -= 1;
3050 // cursor.column = buffer.line_len(cursor.row);
3051 // }
3052 // new_selection.map(|_| cursor)
3053 // })
3054 // .collect();
3055
3056 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3057 // this.refresh_copilot_suggestions(true, cx);
3058 // });
3059 // }
3060
3061 // pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
3062 // let buffer = self.buffer.read(cx);
3063 // let snapshot = buffer.snapshot(cx);
3064
3065 // let mut edits = Vec::new();
3066 // let mut rows = Vec::new();
3067 // let mut rows_inserted = 0;
3068
3069 // for selection in self.selections.all_adjusted(cx) {
3070 // let cursor = selection.head();
3071 // let row = cursor.row;
3072
3073 // let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
3074
3075 // let newline = "\n".to_string();
3076 // edits.push((start_of_line..start_of_line, newline));
3077
3078 // rows.push(row + rows_inserted);
3079 // rows_inserted += 1;
3080 // }
3081
3082 // self.transact(cx, |editor, cx| {
3083 // editor.edit(edits, cx);
3084
3085 // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
3086 // let mut index = 0;
3087 // s.move_cursors_with(|map, _, _| {
3088 // let row = rows[index];
3089 // index += 1;
3090
3091 // let point = Point::new(row, 0);
3092 // let boundary = map.next_line_boundary(point).1;
3093 // let clipped = map.clip_point(boundary, Bias::Left);
3094
3095 // (clipped, SelectionGoal::None)
3096 // });
3097 // });
3098
3099 // let mut indent_edits = Vec::new();
3100 // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
3101 // for row in rows {
3102 // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
3103 // for (row, indent) in indents {
3104 // if indent.len == 0 {
3105 // continue;
3106 // }
3107
3108 // let text = match indent.kind {
3109 // IndentKind::Space => " ".repeat(indent.len as usize),
3110 // IndentKind::Tab => "\t".repeat(indent.len as usize),
3111 // };
3112 // let point = Point::new(row, 0);
3113 // indent_edits.push((point..point, text));
3114 // }
3115 // }
3116 // editor.edit(indent_edits, cx);
3117 // });
3118 // }
3119
3120 // pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
3121 // let buffer = self.buffer.read(cx);
3122 // let snapshot = buffer.snapshot(cx);
3123
3124 // let mut edits = Vec::new();
3125 // let mut rows = Vec::new();
3126 // let mut rows_inserted = 0;
3127
3128 // for selection in self.selections.all_adjusted(cx) {
3129 // let cursor = selection.head();
3130 // let row = cursor.row;
3131
3132 // let point = Point::new(row + 1, 0);
3133 // let start_of_line = snapshot.clip_point(point, Bias::Left);
3134
3135 // let newline = "\n".to_string();
3136 // edits.push((start_of_line..start_of_line, newline));
3137
3138 // rows_inserted += 1;
3139 // rows.push(row + rows_inserted);
3140 // }
3141
3142 // self.transact(cx, |editor, cx| {
3143 // editor.edit(edits, cx);
3144
3145 // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
3146 // let mut index = 0;
3147 // s.move_cursors_with(|map, _, _| {
3148 // let row = rows[index];
3149 // index += 1;
3150
3151 // let point = Point::new(row, 0);
3152 // let boundary = map.next_line_boundary(point).1;
3153 // let clipped = map.clip_point(boundary, Bias::Left);
3154
3155 // (clipped, SelectionGoal::None)
3156 // });
3157 // });
3158
3159 // let mut indent_edits = Vec::new();
3160 // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
3161 // for row in rows {
3162 // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
3163 // for (row, indent) in indents {
3164 // if indent.len == 0 {
3165 // continue;
3166 // }
3167
3168 // let text = match indent.kind {
3169 // IndentKind::Space => " ".repeat(indent.len as usize),
3170 // IndentKind::Tab => "\t".repeat(indent.len as usize),
3171 // };
3172 // let point = Point::new(row, 0);
3173 // indent_edits.push((point..point, text));
3174 // }
3175 // }
3176 // editor.edit(indent_edits, cx);
3177 // });
3178 // }
3179
3180 // pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
3181 // self.insert_with_autoindent_mode(
3182 // text,
3183 // Some(AutoindentMode::Block {
3184 // original_indent_columns: Vec::new(),
3185 // }),
3186 // cx,
3187 // );
3188 // }
3189
3190 fn insert_with_autoindent_mode(
3191 &mut self,
3192 text: &str,
3193 autoindent_mode: Option<AutoindentMode>,
3194 cx: &mut ViewContext<Self>,
3195 ) {
3196 if self.read_only {
3197 return;
3198 }
3199
3200 let text: Arc<str> = text.into();
3201 self.transact(cx, |this, cx| {
3202 let old_selections = this.selections.all_adjusted(cx);
3203 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
3204 let anchors = {
3205 let snapshot = buffer.read(cx);
3206 old_selections
3207 .iter()
3208 .map(|s| {
3209 let anchor = snapshot.anchor_after(s.head());
3210 s.map(|_| anchor)
3211 })
3212 .collect::<Vec<_>>()
3213 };
3214 buffer.edit(
3215 old_selections
3216 .iter()
3217 .map(|s| (s.start..s.end, text.clone())),
3218 autoindent_mode,
3219 cx,
3220 );
3221 anchors
3222 });
3223
3224 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3225 s.select_anchors(selection_anchors);
3226 })
3227 });
3228 }
3229
3230 // fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
3231 // if !EditorSettings>(cx).show_completions_on_input {
3232 // return;
3233 // }
3234
3235 // let selection = self.selections.newest_anchor();
3236 // if self
3237 // .buffer
3238 // .read(cx)
3239 // .is_completion_trigger(selection.head(), text, cx)
3240 // {
3241 // self.show_completions(&ShowCompletions, cx);
3242 // } else {
3243 // self.hide_context_menu(cx);
3244 // }
3245 // }
3246
3247 // /// If any empty selections is touching the start of its innermost containing autoclose
3248 // /// region, expand it to select the brackets.
3249 // fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
3250 // let selections = self.selections.all::<usize>(cx);
3251 // let buffer = self.buffer.read(cx).read(cx);
3252 // let mut new_selections = Vec::new();
3253 // for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
3254 // if let (Some(region), true) = (region, selection.is_empty()) {
3255 // let mut range = region.range.to_offset(&buffer);
3256 // if selection.start == range.start {
3257 // if range.start >= region.pair.start.len() {
3258 // range.start -= region.pair.start.len();
3259 // if buffer.contains_str_at(range.start, ®ion.pair.start) {
3260 // if buffer.contains_str_at(range.end, ®ion.pair.end) {
3261 // range.end += region.pair.end.len();
3262 // selection.start = range.start;
3263 // selection.end = range.end;
3264 // }
3265 // }
3266 // }
3267 // }
3268 // }
3269 // new_selections.push(selection);
3270 // }
3271
3272 // drop(buffer);
3273 // self.change_selections(None, cx, |selections| selections.select(new_selections));
3274 // }
3275
3276 // /// Iterate the given selections, and for each one, find the smallest surrounding
3277 // /// autoclose region. This uses the ordering of the selections and the autoclose
3278 // /// regions to avoid repeated comparisons.
3279 // fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
3280 // &'a self,
3281 // selections: impl IntoIterator<Item = Selection<D>>,
3282 // buffer: &'a MultiBufferSnapshot,
3283 // ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
3284 // let mut i = 0;
3285 // let mut regions = self.autoclose_regions.as_slice();
3286 // selections.into_iter().map(move |selection| {
3287 // let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
3288
3289 // let mut enclosing = None;
3290 // while let Some(pair_state) = regions.get(i) {
3291 // if pair_state.range.end.to_offset(buffer) < range.start {
3292 // regions = ®ions[i + 1..];
3293 // i = 0;
3294 // } else if pair_state.range.start.to_offset(buffer) > range.end {
3295 // break;
3296 // } else {
3297 // if pair_state.selection_id == selection.id {
3298 // enclosing = Some(pair_state);
3299 // }
3300 // i += 1;
3301 // }
3302 // }
3303
3304 // (selection.clone(), enclosing)
3305 // })
3306 // }
3307
3308 /// Remove any autoclose regions that no longer contain their selection.
3309 fn invalidate_autoclose_regions(
3310 &mut self,
3311 mut selections: &[Selection<Anchor>],
3312 buffer: &MultiBufferSnapshot,
3313 ) {
3314 self.autoclose_regions.retain(|state| {
3315 let mut i = 0;
3316 while let Some(selection) = selections.get(i) {
3317 if selection.end.cmp(&state.range.start, buffer).is_lt() {
3318 selections = &selections[1..];
3319 continue;
3320 }
3321 if selection.start.cmp(&state.range.end, buffer).is_gt() {
3322 break;
3323 }
3324 if selection.id == state.selection_id {
3325 return true;
3326 } else {
3327 i += 1;
3328 }
3329 }
3330 false
3331 });
3332 }
3333
3334 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
3335 let offset = position.to_offset(buffer);
3336 let (word_range, kind) = buffer.surrounding_word(offset);
3337 if offset > word_range.start && kind == Some(CharKind::Word) {
3338 Some(
3339 buffer
3340 .text_for_range(word_range.start..offset)
3341 .collect::<String>(),
3342 )
3343 } else {
3344 None
3345 }
3346 }
3347
3348 // pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
3349 // todo!();
3350 // // self.refresh_inlay_hints(
3351 // // InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
3352 // // cx,
3353 // // );
3354 // }
3355
3356 // pub fn inlay_hints_enabled(&self) -> bool {
3357 // todo!();
3358 // self.inlay_hint_cache.enabled
3359 // }
3360
3361 fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
3362 if self.project.is_none() || self.mode != EditorMode::Full {
3363 return;
3364 }
3365
3366 let reason_description = reason.description();
3367 let (invalidate_cache, required_languages) = match reason {
3368 InlayHintRefreshReason::Toggle(enabled) => {
3369 self.inlay_hint_cache.enabled = enabled;
3370 if enabled {
3371 (InvalidationStrategy::RefreshRequested, None)
3372 } else {
3373 self.inlay_hint_cache.clear();
3374 self.splice_inlay_hints(
3375 self.visible_inlay_hints(cx)
3376 .iter()
3377 .map(|inlay| inlay.id)
3378 .collect(),
3379 Vec::new(),
3380 cx,
3381 );
3382 return;
3383 }
3384 }
3385 InlayHintRefreshReason::SettingsChange(new_settings) => {
3386 match self.inlay_hint_cache.update_settings(
3387 &self.buffer,
3388 new_settings,
3389 self.visible_inlay_hints(cx),
3390 cx,
3391 ) {
3392 ControlFlow::Break(Some(InlaySplice {
3393 to_remove,
3394 to_insert,
3395 })) => {
3396 self.splice_inlay_hints(to_remove, to_insert, cx);
3397 return;
3398 }
3399 ControlFlow::Break(None) => return,
3400 ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
3401 }
3402 }
3403 InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
3404 if let Some(InlaySplice {
3405 to_remove,
3406 to_insert,
3407 }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
3408 {
3409 self.splice_inlay_hints(to_remove, to_insert, cx);
3410 }
3411 return;
3412 }
3413 InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
3414 InlayHintRefreshReason::BufferEdited(buffer_languages) => {
3415 (InvalidationStrategy::BufferEdited, Some(buffer_languages))
3416 }
3417 InlayHintRefreshReason::RefreshRequested => {
3418 (InvalidationStrategy::RefreshRequested, None)
3419 }
3420 };
3421
3422 if let Some(InlaySplice {
3423 to_remove,
3424 to_insert,
3425 }) = self.inlay_hint_cache.spawn_hint_refresh(
3426 reason_description,
3427 self.excerpt_visible_offsets(required_languages.as_ref(), cx),
3428 invalidate_cache,
3429 cx,
3430 ) {
3431 self.splice_inlay_hints(to_remove, to_insert, cx);
3432 }
3433 }
3434
3435 fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
3436 self.display_map
3437 .read(cx)
3438 .current_inlays()
3439 .filter(move |inlay| {
3440 Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id)
3441 })
3442 .cloned()
3443 .collect()
3444 }
3445
3446 pub fn excerpt_visible_offsets(
3447 &self,
3448 restrict_to_languages: Option<&HashSet<Arc<Language>>>,
3449 cx: &mut ViewContext<Editor>,
3450 ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
3451 let multi_buffer = self.buffer().read(cx);
3452 let multi_buffer_snapshot = multi_buffer.snapshot(cx);
3453 let multi_buffer_visible_start = self
3454 .scroll_manager
3455 .anchor()
3456 .anchor
3457 .to_point(&multi_buffer_snapshot);
3458 let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
3459 multi_buffer_visible_start
3460 + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
3461 Bias::Left,
3462 );
3463 let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
3464 multi_buffer
3465 .range_to_buffer_ranges(multi_buffer_visible_range, cx)
3466 .into_iter()
3467 .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
3468 .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
3469 let buffer = buffer_handle.read(cx);
3470 let language = buffer.language()?;
3471 if let Some(restrict_to_languages) = restrict_to_languages {
3472 if !restrict_to_languages.contains(language) {
3473 return None;
3474 }
3475 }
3476 Some((
3477 excerpt_id,
3478 (
3479 buffer_handle,
3480 buffer.version().clone(),
3481 excerpt_visible_range,
3482 ),
3483 ))
3484 })
3485 .collect()
3486 }
3487
3488 // pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
3489 // TextLayoutDetails {
3490 // font_cache: cx.font_cache().clone(),
3491 // text_layout_cache: cx.text_layout_cache().clone(),
3492 // editor_style: self.style(cx),
3493 // }
3494 // }
3495
3496 fn splice_inlay_hints(
3497 &self,
3498 to_remove: Vec<InlayId>,
3499 to_insert: Vec<Inlay>,
3500 cx: &mut ViewContext<Self>,
3501 ) {
3502 self.display_map.update(cx, |display_map, cx| {
3503 display_map.splice_inlays(to_remove, to_insert, cx);
3504 });
3505 cx.notify();
3506 }
3507
3508 // fn trigger_on_type_formatting(
3509 // &self,
3510 // input: String,
3511 // cx: &mut ViewContext<Self>,
3512 // ) -> Option<Task<Result<()>>> {
3513 // if input.len() != 1 {
3514 // return None;
3515 // }
3516
3517 // let project = self.project.as_ref()?;
3518 // let position = self.selections.newest_anchor().head();
3519 // let (buffer, buffer_position) = self
3520 // .buffer
3521 // .read(cx)
3522 // .text_anchor_for_position(position.clone(), cx)?;
3523
3524 // // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
3525 // // hence we do LSP request & edit on host side only — add formats to host's history.
3526 // let push_to_lsp_host_history = true;
3527 // // If this is not the host, append its history with new edits.
3528 // let push_to_client_history = project.read(cx).is_remote();
3529
3530 // let on_type_formatting = project.update(cx, |project, cx| {
3531 // project.on_type_format(
3532 // buffer.clone(),
3533 // buffer_position,
3534 // input,
3535 // push_to_lsp_host_history,
3536 // cx,
3537 // )
3538 // });
3539 // Some(cx.spawn(|editor, mut cx| async move {
3540 // if let Some(transaction) = on_type_formatting.await? {
3541 // if push_to_client_history {
3542 // buffer.update(&mut cx, |buffer, _| {
3543 // buffer.push_transaction(transaction, Instant::now());
3544 // });
3545 // }
3546 // editor.update(&mut cx, |editor, cx| {
3547 // editor.refresh_document_highlights(cx);
3548 // })?;
3549 // }
3550 // Ok(())
3551 // }))
3552 // }
3553
3554 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
3555 if self.pending_rename.is_some() {
3556 return;
3557 }
3558
3559 let project = if let Some(project) = self.project.clone() {
3560 project
3561 } else {
3562 return;
3563 };
3564
3565 let position = self.selections.newest_anchor().head();
3566 let (buffer, buffer_position) = if let Some(output) = self
3567 .buffer
3568 .read(cx)
3569 .text_anchor_for_position(position.clone(), cx)
3570 {
3571 output
3572 } else {
3573 return;
3574 };
3575
3576 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
3577 let completions = project.update(cx, |project, cx| {
3578 project.completions(&buffer, buffer_position, cx)
3579 });
3580
3581 let id = post_inc(&mut self.next_completion_id);
3582 let task = cx.spawn(|this, mut cx| {
3583 async move {
3584 let menu = if let Some(completions) = completions.await.log_err() {
3585 let mut menu = CompletionsMenu {
3586 id,
3587 initial_position: position,
3588 match_candidates: completions
3589 .iter()
3590 .enumerate()
3591 .map(|(id, completion)| {
3592 StringMatchCandidate::new(
3593 id,
3594 completion.label.text[completion.label.filter_range.clone()]
3595 .into(),
3596 )
3597 })
3598 .collect(),
3599 buffer,
3600 completions: Arc::new(RwLock::new(completions.into())),
3601 matches: Vec::new().into(),
3602 selected_item: 0,
3603 list: Default::default(),
3604 };
3605 menu.filter(query.as_deref(), cx.background_executor().clone())
3606 .await;
3607 if menu.matches.is_empty() {
3608 None
3609 } else {
3610 _ = this.update(&mut cx, |editor, cx| {
3611 menu.pre_resolve_completion_documentation(editor.project.clone(), cx);
3612 });
3613 Some(menu)
3614 }
3615 } else {
3616 None
3617 };
3618
3619 this.update(&mut cx, |this, cx| {
3620 this.completion_tasks.retain(|(task_id, _)| *task_id > id);
3621
3622 let mut context_menu = this.context_menu.write();
3623 match context_menu.as_ref() {
3624 None => {}
3625
3626 Some(ContextMenu::Completions(prev_menu)) => {
3627 if prev_menu.id > id {
3628 return;
3629 }
3630 }
3631
3632 _ => return,
3633 }
3634
3635 if this.focused && menu.is_some() {
3636 let menu = menu.unwrap();
3637 *context_menu = Some(ContextMenu::Completions(menu));
3638 drop(context_menu);
3639 this.discard_copilot_suggestion(cx);
3640 cx.notify();
3641 } else if this.completion_tasks.is_empty() {
3642 // If there are no more completion tasks and the last menu was
3643 // empty, we should hide it. If it was already hidden, we should
3644 // also show the copilot suggestion when available.
3645 drop(context_menu);
3646 if this.hide_context_menu(cx).is_none() {
3647 this.update_visible_copilot_suggestion(cx);
3648 }
3649 }
3650 })?;
3651
3652 Ok::<_, anyhow::Error>(())
3653 }
3654 .log_err()
3655 });
3656 self.completion_tasks.push((id, task));
3657 }
3658
3659 // pub fn confirm_completion(
3660 // &mut self,
3661 // action: &ConfirmCompletion,
3662 // cx: &mut ViewContext<Self>,
3663 // ) -> Option<Task<Result<()>>> {
3664 // use language::ToOffset as _;
3665
3666 // let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
3667 // menu
3668 // } else {
3669 // return None;
3670 // };
3671
3672 // let mat = completions_menu
3673 // .matches
3674 // .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
3675 // let buffer_handle = completions_menu.buffer;
3676 // let completions = completions_menu.completions.read();
3677 // let completion = completions.get(mat.candidate_id)?;
3678
3679 // let snippet;
3680 // let text;
3681 // if completion.is_snippet() {
3682 // snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
3683 // text = snippet.as_ref().unwrap().text.clone();
3684 // } else {
3685 // snippet = None;
3686 // text = completion.new_text.clone();
3687 // };
3688 // let selections = self.selections.all::<usize>(cx);
3689 // let buffer = buffer_handle.read(cx);
3690 // let old_range = completion.old_range.to_offset(buffer);
3691 // let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
3692
3693 // let newest_selection = self.selections.newest_anchor();
3694 // if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
3695 // return None;
3696 // }
3697
3698 // let lookbehind = newest_selection
3699 // .start
3700 // .text_anchor
3701 // .to_offset(buffer)
3702 // .saturating_sub(old_range.start);
3703 // let lookahead = old_range
3704 // .end
3705 // .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
3706 // let mut common_prefix_len = old_text
3707 // .bytes()
3708 // .zip(text.bytes())
3709 // .take_while(|(a, b)| a == b)
3710 // .count();
3711
3712 // let snapshot = self.buffer.read(cx).snapshot(cx);
3713 // let mut range_to_replace: Option<Range<isize>> = None;
3714 // let mut ranges = Vec::new();
3715 // for selection in &selections {
3716 // if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
3717 // let start = selection.start.saturating_sub(lookbehind);
3718 // let end = selection.end + lookahead;
3719 // if selection.id == newest_selection.id {
3720 // range_to_replace = Some(
3721 // ((start + common_prefix_len) as isize - selection.start as isize)
3722 // ..(end as isize - selection.start as isize),
3723 // );
3724 // }
3725 // ranges.push(start + common_prefix_len..end);
3726 // } else {
3727 // common_prefix_len = 0;
3728 // ranges.clear();
3729 // ranges.extend(selections.iter().map(|s| {
3730 // if s.id == newest_selection.id {
3731 // range_to_replace = Some(
3732 // old_range.start.to_offset_utf16(&snapshot).0 as isize
3733 // - selection.start as isize
3734 // ..old_range.end.to_offset_utf16(&snapshot).0 as isize
3735 // - selection.start as isize,
3736 // );
3737 // old_range.clone()
3738 // } else {
3739 // s.start..s.end
3740 // }
3741 // }));
3742 // break;
3743 // }
3744 // }
3745 // let text = &text[common_prefix_len..];
3746
3747 // cx.emit(Event::InputHandled {
3748 // utf16_range_to_replace: range_to_replace,
3749 // text: text.into(),
3750 // });
3751
3752 // self.transact(cx, |this, cx| {
3753 // if let Some(mut snippet) = snippet {
3754 // snippet.text = text.to_string();
3755 // for tabstop in snippet.tabstops.iter_mut().flatten() {
3756 // tabstop.start -= common_prefix_len as isize;
3757 // tabstop.end -= common_prefix_len as isize;
3758 // }
3759
3760 // this.insert_snippet(&ranges, snippet, cx).log_err();
3761 // } else {
3762 // this.buffer.update(cx, |buffer, cx| {
3763 // buffer.edit(
3764 // ranges.iter().map(|range| (range.clone(), text)),
3765 // this.autoindent_mode.clone(),
3766 // cx,
3767 // );
3768 // });
3769 // }
3770
3771 // this.refresh_copilot_suggestions(true, cx);
3772 // });
3773
3774 // let project = self.project.clone()?;
3775 // let apply_edits = project.update(cx, |project, cx| {
3776 // project.apply_additional_edits_for_completion(
3777 // buffer_handle,
3778 // completion.clone(),
3779 // true,
3780 // cx,
3781 // )
3782 // });
3783 // Some(cx.foreground().spawn(async move {
3784 // apply_edits.await?;
3785 // Ok(())
3786 // }))
3787 // }
3788
3789 // pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
3790 // let mut context_menu = self.context_menu.write();
3791 // if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
3792 // *context_menu = None;
3793 // cx.notify();
3794 // return;
3795 // }
3796 // drop(context_menu);
3797
3798 // let deployed_from_indicator = action.deployed_from_indicator;
3799 // let mut task = self.code_actions_task.take();
3800 // cx.spawn(|this, mut cx| async move {
3801 // while let Some(prev_task) = task {
3802 // prev_task.await;
3803 // task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
3804 // }
3805
3806 // this.update(&mut cx, |this, cx| {
3807 // if this.focused {
3808 // if let Some((buffer, actions)) = this.available_code_actions.clone() {
3809 // this.completion_tasks.clear();
3810 // this.discard_copilot_suggestion(cx);
3811 // *this.context_menu.write() =
3812 // Some(ContextMenu::CodeActions(CodeActionsMenu {
3813 // buffer,
3814 // actions,
3815 // selected_item: Default::default(),
3816 // list: Default::default(),
3817 // deployed_from_indicator,
3818 // }));
3819 // }
3820 // }
3821 // })?;
3822
3823 // Ok::<_, anyhow::Error>(())
3824 // })
3825 // .detach_and_log_err(cx);
3826 // }
3827
3828 // pub fn confirm_code_action(
3829 // workspace: &mut Workspace,
3830 // action: &ConfirmCodeAction,
3831 // cx: &mut ViewContext<Workspace>,
3832 // ) -> Option<Task<Result<()>>> {
3833 // let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
3834 // let actions_menu = if let ContextMenu::CodeActions(menu) =
3835 // editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
3836 // {
3837 // menu
3838 // } else {
3839 // return None;
3840 // };
3841 // let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
3842 // let action = actions_menu.actions.get(action_ix)?.clone();
3843 // let title = action.lsp_action.title.clone();
3844 // let buffer = actions_menu.buffer;
3845
3846 // let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
3847 // project.apply_code_action(buffer, action, true, cx)
3848 // });
3849 // let editor = editor.downgrade();
3850 // Some(cx.spawn(|workspace, cx| async move {
3851 // let project_transaction = apply_code_actions.await?;
3852 // Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
3853 // }))
3854 // }
3855
3856 // async fn open_project_transaction(
3857 // this: &WeakViewHandle<Editor
3858 // workspace: WeakViewHandle<Workspace
3859 // transaction: ProjectTransaction,
3860 // title: String,
3861 // mut cx: AsyncAppContext,
3862 // ) -> Result<()> {
3863 // let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?;
3864
3865 // let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
3866 // entries.sort_unstable_by_key(|(buffer, _)| {
3867 // buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
3868 // });
3869
3870 // // If the project transaction's edits are all contained within this editor, then
3871 // // avoid opening a new editor to display them.
3872
3873 // if let Some((buffer, transaction)) = entries.first() {
3874 // if entries.len() == 1 {
3875 // let excerpt = this.read_with(&cx, |editor, cx| {
3876 // editor
3877 // .buffer()
3878 // .read(cx)
3879 // .excerpt_containing(editor.selections.newest_anchor().head(), cx)
3880 // })?;
3881 // if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
3882 // if excerpted_buffer == *buffer {
3883 // let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
3884 // let excerpt_range = excerpt_range.to_offset(buffer);
3885 // buffer
3886 // .edited_ranges_for_transaction::<usize>(transaction)
3887 // .all(|range| {
3888 // excerpt_range.start <= range.start
3889 // && excerpt_range.end >= range.end
3890 // })
3891 // });
3892
3893 // if all_edits_within_excerpt {
3894 // return Ok(());
3895 // }
3896 // }
3897 // }
3898 // }
3899 // } else {
3900 // return Ok(());
3901 // }
3902
3903 // let mut ranges_to_highlight = Vec::new();
3904 // let excerpt_buffer = cx.build_model(|cx| {
3905 // let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
3906 // for (buffer_handle, transaction) in &entries {
3907 // let buffer = buffer_handle.read(cx);
3908 // ranges_to_highlight.extend(
3909 // multibuffer.push_excerpts_with_context_lines(
3910 // buffer_handle.clone(),
3911 // buffer
3912 // .edited_ranges_for_transaction::<usize>(transaction)
3913 // .collect(),
3914 // 1,
3915 // cx,
3916 // ),
3917 // );
3918 // }
3919 // multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
3920 // multibuffer
3921 // });
3922
3923 // workspace.update(&mut cx, |workspace, cx| {
3924 // let project = workspace.project().clone();
3925 // let editor =
3926 // cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
3927 // workspace.add_item(Box::new(editor.clone()), cx);
3928 // editor.update(cx, |editor, cx| {
3929 // editor.highlight_background::<Self>(
3930 // ranges_to_highlight,
3931 // |theme| theme.editor.highlighted_line_background,
3932 // cx,
3933 // );
3934 // });
3935 // })?;
3936
3937 // Ok(())
3938 // }
3939
3940 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
3941 let project = self.project.clone()?;
3942 let buffer = self.buffer.read(cx);
3943 let newest_selection = self.selections.newest_anchor().clone();
3944 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
3945 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
3946 if start_buffer != end_buffer {
3947 return None;
3948 }
3949
3950 self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
3951 cx.background_executor()
3952 .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
3953 .await;
3954
3955 let actions = if let Ok(code_actions) = project.update(&mut cx, |project, cx| {
3956 project.code_actions(&start_buffer, start..end, cx)
3957 }) {
3958 code_actions.await.log_err()
3959 } else {
3960 None
3961 };
3962
3963 this.update(&mut cx, |this, cx| {
3964 this.available_code_actions = actions.and_then(|actions| {
3965 if actions.is_empty() {
3966 None
3967 } else {
3968 Some((start_buffer, actions.into()))
3969 }
3970 });
3971 cx.notify();
3972 })
3973 .log_err();
3974 }));
3975 None
3976 }
3977
3978 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
3979 if self.pending_rename.is_some() {
3980 return None;
3981 }
3982
3983 let project = self.project.clone()?;
3984 let buffer = self.buffer.read(cx);
3985 let newest_selection = self.selections.newest_anchor().clone();
3986 let cursor_position = newest_selection.head();
3987 let (cursor_buffer, cursor_buffer_position) =
3988 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
3989 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
3990 if cursor_buffer != tail_buffer {
3991 return None;
3992 }
3993
3994 self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
3995 cx.background_executor()
3996 .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
3997 .await;
3998
3999 let highlights = if let Some(highlights) = project
4000 .update(&mut cx, |project, cx| {
4001 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
4002 })
4003 .log_err()
4004 {
4005 highlights.await.log_err()
4006 } else {
4007 None
4008 };
4009
4010 if let Some(highlights) = highlights {
4011 this.update(&mut cx, |this, cx| {
4012 if this.pending_rename.is_some() {
4013 return;
4014 }
4015
4016 let buffer_id = cursor_position.buffer_id;
4017 let buffer = this.buffer.read(cx);
4018 if !buffer
4019 .text_anchor_for_position(cursor_position, cx)
4020 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
4021 {
4022 return;
4023 }
4024
4025 let cursor_buffer_snapshot = cursor_buffer.read(cx);
4026 let mut write_ranges = Vec::new();
4027 let mut read_ranges = Vec::new();
4028 for highlight in highlights {
4029 for (excerpt_id, excerpt_range) in
4030 buffer.excerpts_for_buffer(&cursor_buffer, cx)
4031 {
4032 let start = highlight
4033 .range
4034 .start
4035 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
4036 let end = highlight
4037 .range
4038 .end
4039 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
4040 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
4041 continue;
4042 }
4043
4044 let range = Anchor {
4045 buffer_id,
4046 excerpt_id: excerpt_id.clone(),
4047 text_anchor: start,
4048 }..Anchor {
4049 buffer_id,
4050 excerpt_id,
4051 text_anchor: end,
4052 };
4053 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
4054 write_ranges.push(range);
4055 } else {
4056 read_ranges.push(range);
4057 }
4058 }
4059 }
4060
4061 this.highlight_background::<DocumentHighlightRead>(
4062 read_ranges,
4063 |theme| todo!("theme.editor.document_highlight_read_background"),
4064 cx,
4065 );
4066 this.highlight_background::<DocumentHighlightWrite>(
4067 write_ranges,
4068 |theme| todo!("theme.editor.document_highlight_write_background"),
4069 cx,
4070 );
4071 cx.notify();
4072 })
4073 .log_err();
4074 }
4075 }));
4076 None
4077 }
4078
4079 fn refresh_copilot_suggestions(
4080 &mut self,
4081 debounce: bool,
4082 cx: &mut ViewContext<Self>,
4083 ) -> Option<()> {
4084 let copilot = Copilot::global(cx)?;
4085 if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
4086 self.clear_copilot_suggestions(cx);
4087 return None;
4088 }
4089 self.update_visible_copilot_suggestion(cx);
4090
4091 let snapshot = self.buffer.read(cx).snapshot(cx);
4092 let cursor = self.selections.newest_anchor().head();
4093 if !self.is_copilot_enabled_at(cursor, &snapshot, cx) {
4094 self.clear_copilot_suggestions(cx);
4095 return None;
4096 }
4097
4098 let (buffer, buffer_position) =
4099 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
4100 self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move {
4101 if debounce {
4102 cx.background_executor()
4103 .timer(COPILOT_DEBOUNCE_TIMEOUT)
4104 .await;
4105 }
4106
4107 let completions = copilot
4108 .update(&mut cx, |copilot, cx| {
4109 copilot.completions(&buffer, buffer_position, cx)
4110 })
4111 .log_err()
4112 .unwrap_or(Task::ready(Ok(Vec::new())))
4113 .await
4114 .log_err()
4115 .into_iter()
4116 .flatten()
4117 .collect_vec();
4118
4119 this.update(&mut cx, |this, cx| {
4120 if !completions.is_empty() {
4121 this.copilot_state.cycled = false;
4122 this.copilot_state.pending_cycling_refresh = Task::ready(None);
4123 this.copilot_state.completions.clear();
4124 this.copilot_state.active_completion_index = 0;
4125 this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
4126 for completion in completions {
4127 this.copilot_state.push_completion(completion);
4128 }
4129 this.update_visible_copilot_suggestion(cx);
4130 }
4131 })
4132 .log_err()?;
4133 Some(())
4134 });
4135
4136 Some(())
4137 }
4138
4139 fn cycle_copilot_suggestions(
4140 &mut self,
4141 direction: Direction,
4142 cx: &mut ViewContext<Self>,
4143 ) -> Option<()> {
4144 let copilot = Copilot::global(cx)?;
4145 if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
4146 return None;
4147 }
4148
4149 if self.copilot_state.cycled {
4150 self.copilot_state.cycle_completions(direction);
4151 self.update_visible_copilot_suggestion(cx);
4152 } else {
4153 let cursor = self.selections.newest_anchor().head();
4154 let (buffer, buffer_position) =
4155 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
4156 self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move {
4157 let completions = copilot
4158 .update(&mut cx, |copilot, cx| {
4159 copilot.completions_cycling(&buffer, buffer_position, cx)
4160 })
4161 .log_err()?
4162 .await;
4163
4164 this.update(&mut cx, |this, cx| {
4165 this.copilot_state.cycled = true;
4166 for completion in completions.log_err().into_iter().flatten() {
4167 this.copilot_state.push_completion(completion);
4168 }
4169 this.copilot_state.cycle_completions(direction);
4170 this.update_visible_copilot_suggestion(cx);
4171 })
4172 .log_err()?;
4173
4174 Some(())
4175 });
4176 }
4177
4178 Some(())
4179 }
4180
4181 fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
4182 if !self.has_active_copilot_suggestion(cx) {
4183 self.refresh_copilot_suggestions(false, cx);
4184 return;
4185 }
4186
4187 self.update_visible_copilot_suggestion(cx);
4188 }
4189
4190 fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
4191 if self.has_active_copilot_suggestion(cx) {
4192 self.cycle_copilot_suggestions(Direction::Next, cx);
4193 } else {
4194 let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
4195 if is_copilot_disabled {
4196 todo!();
4197 // cx.propagate();
4198 }
4199 }
4200 }
4201
4202 fn previous_copilot_suggestion(
4203 &mut self,
4204 _: &copilot::PreviousSuggestion,
4205 cx: &mut ViewContext<Self>,
4206 ) {
4207 if self.has_active_copilot_suggestion(cx) {
4208 self.cycle_copilot_suggestions(Direction::Prev, cx);
4209 } else {
4210 let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
4211 if is_copilot_disabled {
4212 todo!();
4213 // cx.propagate_action();
4214 }
4215 }
4216 }
4217
4218 fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
4219 if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
4220 if let Some((copilot, completion)) =
4221 Copilot::global(cx).zip(self.copilot_state.active_completion())
4222 {
4223 copilot
4224 .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
4225 .detach_and_log_err(cx);
4226
4227 self.report_copilot_event(Some(completion.uuid.clone()), true, cx)
4228 }
4229 cx.emit(Event::InputHandled {
4230 utf16_range_to_replace: None,
4231 text: suggestion.text.to_string().into(),
4232 });
4233 self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
4234 cx.notify();
4235 true
4236 } else {
4237 false
4238 }
4239 }
4240
4241 fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
4242 if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
4243 if let Some(copilot) = Copilot::global(cx) {
4244 copilot
4245 .update(cx, |copilot, cx| {
4246 copilot.discard_completions(&self.copilot_state.completions, cx)
4247 })
4248 .detach_and_log_err(cx);
4249
4250 self.report_copilot_event(None, false, cx)
4251 }
4252
4253 self.display_map.update(cx, |map, cx| {
4254 map.splice_inlays(vec![suggestion.id], Vec::new(), cx)
4255 });
4256 cx.notify();
4257 true
4258 } else {
4259 false
4260 }
4261 }
4262
4263 fn is_copilot_enabled_at(
4264 &self,
4265 location: Anchor,
4266 snapshot: &MultiBufferSnapshot,
4267 cx: &mut ViewContext<Self>,
4268 ) -> bool {
4269 let file = snapshot.file_at(location);
4270 let language = snapshot.language_at(location);
4271 let settings = all_language_settings(file, cx);
4272 settings.copilot_enabled(language, file.map(|f| f.path().as_ref()))
4273 }
4274
4275 fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
4276 if let Some(suggestion) = self.copilot_state.suggestion.as_ref() {
4277 let buffer = self.buffer.read(cx).read(cx);
4278 suggestion.position.is_valid(&buffer)
4279 } else {
4280 false
4281 }
4282 }
4283
4284 fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
4285 let suggestion = self.copilot_state.suggestion.take()?;
4286 self.display_map.update(cx, |map, cx| {
4287 map.splice_inlays(vec![suggestion.id], Default::default(), cx);
4288 });
4289 let buffer = self.buffer.read(cx).read(cx);
4290
4291 if suggestion.position.is_valid(&buffer) {
4292 Some(suggestion)
4293 } else {
4294 None
4295 }
4296 }
4297
4298 fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
4299 let snapshot = self.buffer.read(cx).snapshot(cx);
4300 let selection = self.selections.newest_anchor();
4301 let cursor = selection.head();
4302
4303 if self.context_menu.read().is_some()
4304 || !self.completion_tasks.is_empty()
4305 || selection.start != selection.end
4306 {
4307 self.discard_copilot_suggestion(cx);
4308 } else if let Some(text) = self
4309 .copilot_state
4310 .text_for_active_completion(cursor, &snapshot)
4311 {
4312 let text = Rope::from(text);
4313 let mut to_remove = Vec::new();
4314 if let Some(suggestion) = self.copilot_state.suggestion.take() {
4315 to_remove.push(suggestion.id);
4316 }
4317
4318 let suggestion_inlay =
4319 Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
4320 self.copilot_state.suggestion = Some(suggestion_inlay.clone());
4321 self.display_map.update(cx, move |map, cx| {
4322 map.splice_inlays(to_remove, vec![suggestion_inlay], cx)
4323 });
4324 cx.notify();
4325 } else {
4326 self.discard_copilot_suggestion(cx);
4327 }
4328 }
4329
4330 fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
4331 self.copilot_state = Default::default();
4332 self.discard_copilot_suggestion(cx);
4333 }
4334
4335 // pub fn render_code_actions_indicator(
4336 // &self,
4337 // style: &EditorStyle,
4338 // is_active: bool,
4339 // cx: &mut ViewContext<Self>,
4340 // ) -> Option<AnyElement<Self>> {
4341 // if self.available_code_actions.is_some() {
4342 // enum CodeActions {}
4343 // Some(
4344 // MouseEventHandler::new::<CodeActions, _>(0, cx, |state, _| {
4345 // Svg::new("icons/bolt.svg").with_color(
4346 // style
4347 // .code_actions
4348 // .indicator
4349 // .in_state(is_active)
4350 // .style_for(state)
4351 // .color,
4352 // )
4353 // })
4354 // .with_cursor_style(CursorStyle::PointingHand)
4355 // .with_padding(Padding::uniform(3.))
4356 // .on_down(MouseButton::Left, |_, this, cx| {
4357 // this.toggle_code_actions(
4358 // &ToggleCodeActions {
4359 // deployed_from_indicator: true,
4360 // },
4361 // cx,
4362 // );
4363 // })
4364 // .into_any(),
4365 // )
4366 // } else {
4367 // None
4368 // }
4369 // }
4370
4371 // pub fn render_fold_indicators(
4372 // &self,
4373 // fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
4374 // style: &EditorStyle,
4375 // gutter_hovered: bool,
4376 // line_height: f32,
4377 // gutter_margin: f32,
4378 // cx: &mut ViewContext<Self>,
4379 // ) -> Vec<Option<AnyElement<Self>>> {
4380 // enum FoldIndicators {}
4381
4382 // let style = style.folds.clone();
4383
4384 // fold_data
4385 // .iter()
4386 // .enumerate()
4387 // .map(|(ix, fold_data)| {
4388 // fold_data
4389 // .map(|(fold_status, buffer_row, active)| {
4390 // (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
4391 // MouseEventHandler::new::<FoldIndicators, _>(
4392 // ix as usize,
4393 // cx,
4394 // |mouse_state, _| {
4395 // Svg::new(match fold_status {
4396 // FoldStatus::Folded => style.folded_icon.clone(),
4397 // FoldStatus::Foldable => style.foldable_icon.clone(),
4398 // })
4399 // .with_color(
4400 // style
4401 // .indicator
4402 // .in_state(fold_status == FoldStatus::Folded)
4403 // .style_for(mouse_state)
4404 // .color,
4405 // )
4406 // .constrained()
4407 // .with_width(gutter_margin * style.icon_margin_scale)
4408 // .aligned()
4409 // .constrained()
4410 // .with_height(line_height)
4411 // .with_width(gutter_margin)
4412 // .aligned()
4413 // },
4414 // )
4415 // .with_cursor_style(CursorStyle::PointingHand)
4416 // .with_padding(Padding::uniform(3.))
4417 // .on_click(MouseButton::Left, {
4418 // move |_, editor, cx| match fold_status {
4419 // FoldStatus::Folded => {
4420 // editor.unfold_at(&UnfoldAt { buffer_row }, cx);
4421 // }
4422 // FoldStatus::Foldable => {
4423 // editor.fold_at(&FoldAt { buffer_row }, cx);
4424 // }
4425 // }
4426 // })
4427 // .into_any()
4428 // })
4429 // })
4430 // .flatten()
4431 // })
4432 // .collect()
4433 // }
4434
4435 // pub fn context_menu_visible(&self) -> bool {
4436 // self.context_menu
4437 // .read()
4438 // .as_ref()
4439 // .map_or(false, |menu| menu.visible())
4440 // }
4441
4442 // pub fn render_context_menu(
4443 // &self,
4444 // cursor_position: DisplayPoint,
4445 // style: EditorStyle,
4446 // cx: &mut ViewContext<Editor>,
4447 // ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
4448 // self.context_menu.read().as_ref().map(|menu| {
4449 // menu.render(
4450 // cursor_position,
4451 // style,
4452 // self.workspace.as_ref().map(|(w, _)| w.clone()),
4453 // cx,
4454 // )
4455 // })
4456 // }
4457
4458 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
4459 cx.notify();
4460 self.completion_tasks.clear();
4461 let context_menu = self.context_menu.write().take();
4462 if context_menu.is_some() {
4463 self.update_visible_copilot_suggestion(cx);
4464 }
4465 context_menu
4466 }
4467
4468 // pub fn insert_snippet(
4469 // &mut self,
4470 // insertion_ranges: &[Range<usize>],
4471 // snippet: Snippet,
4472 // cx: &mut ViewContext<Self>,
4473 // ) -> Result<()> {
4474 // let tabstops = self.buffer.update(cx, |buffer, cx| {
4475 // let snippet_text: Arc<str> = snippet.text.clone().into();
4476 // buffer.edit(
4477 // insertion_ranges
4478 // .iter()
4479 // .cloned()
4480 // .map(|range| (range, snippet_text.clone())),
4481 // Some(AutoindentMode::EachLine),
4482 // cx,
4483 // );
4484
4485 // let snapshot = &*buffer.read(cx);
4486 // let snippet = &snippet;
4487 // snippet
4488 // .tabstops
4489 // .iter()
4490 // .map(|tabstop| {
4491 // let mut tabstop_ranges = tabstop
4492 // .iter()
4493 // .flat_map(|tabstop_range| {
4494 // let mut delta = 0_isize;
4495 // insertion_ranges.iter().map(move |insertion_range| {
4496 // let insertion_start = insertion_range.start as isize + delta;
4497 // delta +=
4498 // snippet.text.len() as isize - insertion_range.len() as isize;
4499
4500 // let start = snapshot.anchor_before(
4501 // (insertion_start + tabstop_range.start) as usize,
4502 // );
4503 // let end = snapshot
4504 // .anchor_after((insertion_start + tabstop_range.end) as usize);
4505 // start..end
4506 // })
4507 // })
4508 // .collect::<Vec<_>>();
4509 // tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
4510 // tabstop_ranges
4511 // })
4512 // .collect::<Vec<_>>()
4513 // });
4514
4515 // if let Some(tabstop) = tabstops.first() {
4516 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4517 // s.select_ranges(tabstop.iter().cloned());
4518 // });
4519 // self.snippet_stack.push(SnippetState {
4520 // active_index: 0,
4521 // ranges: tabstops,
4522 // });
4523 // }
4524
4525 // Ok(())
4526 // }
4527
4528 // pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
4529 // self.move_to_snippet_tabstop(Bias::Right, cx)
4530 // }
4531
4532 // pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
4533 // self.move_to_snippet_tabstop(Bias::Left, cx)
4534 // }
4535
4536 // pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
4537 // if let Some(mut snippet) = self.snippet_stack.pop() {
4538 // match bias {
4539 // Bias::Left => {
4540 // if snippet.active_index > 0 {
4541 // snippet.active_index -= 1;
4542 // } else {
4543 // self.snippet_stack.push(snippet);
4544 // return false;
4545 // }
4546 // }
4547 // Bias::Right => {
4548 // if snippet.active_index + 1 < snippet.ranges.len() {
4549 // snippet.active_index += 1;
4550 // } else {
4551 // self.snippet_stack.push(snippet);
4552 // return false;
4553 // }
4554 // }
4555 // }
4556 // if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
4557 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4558 // s.select_anchor_ranges(current_ranges.iter().cloned())
4559 // });
4560 // // If snippet state is not at the last tabstop, push it back on the stack
4561 // if snippet.active_index + 1 < snippet.ranges.len() {
4562 // self.snippet_stack.push(snippet);
4563 // }
4564 // return true;
4565 // }
4566 // }
4567
4568 // false
4569 // }
4570
4571 // pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
4572 // self.transact(cx, |this, cx| {
4573 // this.select_all(&SelectAll, cx);
4574 // this.insert("", cx);
4575 // });
4576 // }
4577
4578 // pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
4579 // self.transact(cx, |this, cx| {
4580 // this.select_autoclose_pair(cx);
4581 // let mut selections = this.selections.all::<Point>(cx);
4582 // if !this.selections.line_mode {
4583 // let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
4584 // for selection in &mut selections {
4585 // if selection.is_empty() {
4586 // let old_head = selection.head();
4587 // let mut new_head =
4588 // movement::left(&display_map, old_head.to_display_point(&display_map))
4589 // .to_point(&display_map);
4590 // if let Some((buffer, line_buffer_range)) = display_map
4591 // .buffer_snapshot
4592 // .buffer_line_for_row(old_head.row)
4593 // {
4594 // let indent_size =
4595 // buffer.indent_size_for_line(line_buffer_range.start.row);
4596 // let indent_len = match indent_size.kind {
4597 // IndentKind::Space => {
4598 // buffer.settings_at(line_buffer_range.start, cx).tab_size
4599 // }
4600 // IndentKind::Tab => NonZeroU32::new(1).unwrap(),
4601 // };
4602 // if old_head.column <= indent_size.len && old_head.column > 0 {
4603 // let indent_len = indent_len.get();
4604 // new_head = cmp::min(
4605 // new_head,
4606 // Point::new(
4607 // old_head.row,
4608 // ((old_head.column - 1) / indent_len) * indent_len,
4609 // ),
4610 // );
4611 // }
4612 // }
4613
4614 // selection.set_head(new_head, SelectionGoal::None);
4615 // }
4616 // }
4617 // }
4618
4619 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4620 // this.insert("", cx);
4621 // this.refresh_copilot_suggestions(true, cx);
4622 // });
4623 // }
4624
4625 // pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
4626 // self.transact(cx, |this, cx| {
4627 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4628 // let line_mode = s.line_mode;
4629 // s.move_with(|map, selection| {
4630 // if selection.is_empty() && !line_mode {
4631 // let cursor = movement::right(map, selection.head());
4632 // selection.end = cursor;
4633 // selection.reversed = true;
4634 // selection.goal = SelectionGoal::None;
4635 // }
4636 // })
4637 // });
4638 // this.insert("", cx);
4639 // this.refresh_copilot_suggestions(true, cx);
4640 // });
4641 // }
4642
4643 // pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
4644 // if self.move_to_prev_snippet_tabstop(cx) {
4645 // return;
4646 // }
4647
4648 // self.outdent(&Outdent, cx);
4649 // }
4650
4651 // pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
4652 // if self.move_to_next_snippet_tabstop(cx) {
4653 // return;
4654 // }
4655
4656 // let mut selections = self.selections.all_adjusted(cx);
4657 // let buffer = self.buffer.read(cx);
4658 // let snapshot = buffer.snapshot(cx);
4659 // let rows_iter = selections.iter().map(|s| s.head().row);
4660 // let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
4661
4662 // let mut edits = Vec::new();
4663 // let mut prev_edited_row = 0;
4664 // let mut row_delta = 0;
4665 // for selection in &mut selections {
4666 // if selection.start.row != prev_edited_row {
4667 // row_delta = 0;
4668 // }
4669 // prev_edited_row = selection.end.row;
4670
4671 // // If the selection is non-empty, then increase the indentation of the selected lines.
4672 // if !selection.is_empty() {
4673 // row_delta =
4674 // Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
4675 // continue;
4676 // }
4677
4678 // // If the selection is empty and the cursor is in the leading whitespace before the
4679 // // suggested indentation, then auto-indent the line.
4680 // let cursor = selection.head();
4681 // let current_indent = snapshot.indent_size_for_line(cursor.row);
4682 // if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
4683 // if cursor.column < suggested_indent.len
4684 // && cursor.column <= current_indent.len
4685 // && current_indent.len <= suggested_indent.len
4686 // {
4687 // selection.start = Point::new(cursor.row, suggested_indent.len);
4688 // selection.end = selection.start;
4689 // if row_delta == 0 {
4690 // edits.extend(Buffer::edit_for_indent_size_adjustment(
4691 // cursor.row,
4692 // current_indent,
4693 // suggested_indent,
4694 // ));
4695 // row_delta = suggested_indent.len - current_indent.len;
4696 // }
4697 // continue;
4698 // }
4699 // }
4700
4701 // // Accept copilot suggestion if there is only one selection and the cursor is not
4702 // // in the leading whitespace.
4703 // if self.selections.count() == 1
4704 // && cursor.column >= current_indent.len
4705 // && self.has_active_copilot_suggestion(cx)
4706 // {
4707 // self.accept_copilot_suggestion(cx);
4708 // return;
4709 // }
4710
4711 // // Otherwise, insert a hard or soft tab.
4712 // let settings = buffer.settings_at(cursor, cx);
4713 // let tab_size = if settings.hard_tabs {
4714 // IndentSize::tab()
4715 // } else {
4716 // let tab_size = settings.tab_size.get();
4717 // let char_column = snapshot
4718 // .text_for_range(Point::new(cursor.row, 0)..cursor)
4719 // .flat_map(str::chars)
4720 // .count()
4721 // + row_delta as usize;
4722 // let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
4723 // IndentSize::spaces(chars_to_next_tab_stop)
4724 // };
4725 // selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
4726 // selection.end = selection.start;
4727 // edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
4728 // row_delta += tab_size.len;
4729 // }
4730
4731 // self.transact(cx, |this, cx| {
4732 // this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
4733 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4734 // this.refresh_copilot_suggestions(true, cx);
4735 // });
4736 // }
4737
4738 // pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
4739 // let mut selections = self.selections.all::<Point>(cx);
4740 // let mut prev_edited_row = 0;
4741 // let mut row_delta = 0;
4742 // let mut edits = Vec::new();
4743 // let buffer = self.buffer.read(cx);
4744 // let snapshot = buffer.snapshot(cx);
4745 // for selection in &mut selections {
4746 // if selection.start.row != prev_edited_row {
4747 // row_delta = 0;
4748 // }
4749 // prev_edited_row = selection.end.row;
4750
4751 // row_delta =
4752 // Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
4753 // }
4754
4755 // self.transact(cx, |this, cx| {
4756 // this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
4757 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4758 // });
4759 // }
4760
4761 // fn indent_selection(
4762 // buffer: &MultiBuffer,
4763 // snapshot: &MultiBufferSnapshot,
4764 // selection: &mut Selection<Point>,
4765 // edits: &mut Vec<(Range<Point>, String)>,
4766 // delta_for_start_row: u32,
4767 // cx: &AppContext,
4768 // ) -> u32 {
4769 // let settings = buffer.settings_at(selection.start, cx);
4770 // let tab_size = settings.tab_size.get();
4771 // let indent_kind = if settings.hard_tabs {
4772 // IndentKind::Tab
4773 // } else {
4774 // IndentKind::Space
4775 // };
4776 // let mut start_row = selection.start.row;
4777 // let mut end_row = selection.end.row + 1;
4778
4779 // // If a selection ends at the beginning of a line, don't indent
4780 // // that last line.
4781 // if selection.end.column == 0 {
4782 // end_row -= 1;
4783 // }
4784
4785 // // Avoid re-indenting a row that has already been indented by a
4786 // // previous selection, but still update this selection's column
4787 // // to reflect that indentation.
4788 // if delta_for_start_row > 0 {
4789 // start_row += 1;
4790 // selection.start.column += delta_for_start_row;
4791 // if selection.end.row == selection.start.row {
4792 // selection.end.column += delta_for_start_row;
4793 // }
4794 // }
4795
4796 // let mut delta_for_end_row = 0;
4797 // for row in start_row..end_row {
4798 // let current_indent = snapshot.indent_size_for_line(row);
4799 // let indent_delta = match (current_indent.kind, indent_kind) {
4800 // (IndentKind::Space, IndentKind::Space) => {
4801 // let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
4802 // IndentSize::spaces(columns_to_next_tab_stop)
4803 // }
4804 // (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
4805 // (_, IndentKind::Tab) => IndentSize::tab(),
4806 // };
4807
4808 // let row_start = Point::new(row, 0);
4809 // edits.push((
4810 // row_start..row_start,
4811 // indent_delta.chars().collect::<String>(),
4812 // ));
4813
4814 // // Update this selection's endpoints to reflect the indentation.
4815 // if row == selection.start.row {
4816 // selection.start.column += indent_delta.len;
4817 // }
4818 // if row == selection.end.row {
4819 // selection.end.column += indent_delta.len;
4820 // delta_for_end_row = indent_delta.len;
4821 // }
4822 // }
4823
4824 // if selection.start.row == selection.end.row {
4825 // delta_for_start_row + delta_for_end_row
4826 // } else {
4827 // delta_for_end_row
4828 // }
4829 // }
4830
4831 // pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
4832 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4833 // let selections = self.selections.all::<Point>(cx);
4834 // let mut deletion_ranges = Vec::new();
4835 // let mut last_outdent = None;
4836 // {
4837 // let buffer = self.buffer.read(cx);
4838 // let snapshot = buffer.snapshot(cx);
4839 // for selection in &selections {
4840 // let settings = buffer.settings_at(selection.start, cx);
4841 // let tab_size = settings.tab_size.get();
4842 // let mut rows = selection.spanned_rows(false, &display_map);
4843
4844 // // Avoid re-outdenting a row that has already been outdented by a
4845 // // previous selection.
4846 // if let Some(last_row) = last_outdent {
4847 // if last_row == rows.start {
4848 // rows.start += 1;
4849 // }
4850 // }
4851
4852 // for row in rows {
4853 // let indent_size = snapshot.indent_size_for_line(row);
4854 // if indent_size.len > 0 {
4855 // let deletion_len = match indent_size.kind {
4856 // IndentKind::Space => {
4857 // let columns_to_prev_tab_stop = indent_size.len % tab_size;
4858 // if columns_to_prev_tab_stop == 0 {
4859 // tab_size
4860 // } else {
4861 // columns_to_prev_tab_stop
4862 // }
4863 // }
4864 // IndentKind::Tab => 1,
4865 // };
4866 // deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
4867 // last_outdent = Some(row);
4868 // }
4869 // }
4870 // }
4871 // }
4872
4873 // self.transact(cx, |this, cx| {
4874 // this.buffer.update(cx, |buffer, cx| {
4875 // let empty_str: Arc<str> = "".into();
4876 // buffer.edit(
4877 // deletion_ranges
4878 // .into_iter()
4879 // .map(|range| (range, empty_str.clone())),
4880 // None,
4881 // cx,
4882 // );
4883 // });
4884 // let selections = this.selections.all::<usize>(cx);
4885 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4886 // });
4887 // }
4888
4889 // pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
4890 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4891 // let selections = self.selections.all::<Point>(cx);
4892
4893 // let mut new_cursors = Vec::new();
4894 // let mut edit_ranges = Vec::new();
4895 // let mut selections = selections.iter().peekable();
4896 // while let Some(selection) = selections.next() {
4897 // let mut rows = selection.spanned_rows(false, &display_map);
4898 // let goal_display_column = selection.head().to_display_point(&display_map).column();
4899
4900 // // Accumulate contiguous regions of rows that we want to delete.
4901 // while let Some(next_selection) = selections.peek() {
4902 // let next_rows = next_selection.spanned_rows(false, &display_map);
4903 // if next_rows.start <= rows.end {
4904 // rows.end = next_rows.end;
4905 // selections.next().unwrap();
4906 // } else {
4907 // break;
4908 // }
4909 // }
4910
4911 // let buffer = &display_map.buffer_snapshot;
4912 // let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
4913 // let edit_end;
4914 // let cursor_buffer_row;
4915 // if buffer.max_point().row >= rows.end {
4916 // // If there's a line after the range, delete the \n from the end of the row range
4917 // // and position the cursor on the next line.
4918 // edit_end = Point::new(rows.end, 0).to_offset(buffer);
4919 // cursor_buffer_row = rows.end;
4920 // } else {
4921 // // If there isn't a line after the range, delete the \n from the line before the
4922 // // start of the row range and position the cursor there.
4923 // edit_start = edit_start.saturating_sub(1);
4924 // edit_end = buffer.len();
4925 // cursor_buffer_row = rows.start.saturating_sub(1);
4926 // }
4927
4928 // let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
4929 // *cursor.column_mut() =
4930 // cmp::min(goal_display_column, display_map.line_len(cursor.row()));
4931
4932 // new_cursors.push((
4933 // selection.id,
4934 // buffer.anchor_after(cursor.to_point(&display_map)),
4935 // ));
4936 // edit_ranges.push(edit_start..edit_end);
4937 // }
4938
4939 // self.transact(cx, |this, cx| {
4940 // let buffer = this.buffer.update(cx, |buffer, cx| {
4941 // let empty_str: Arc<str> = "".into();
4942 // buffer.edit(
4943 // edit_ranges
4944 // .into_iter()
4945 // .map(|range| (range, empty_str.clone())),
4946 // None,
4947 // cx,
4948 // );
4949 // buffer.snapshot(cx)
4950 // });
4951 // let new_selections = new_cursors
4952 // .into_iter()
4953 // .map(|(id, cursor)| {
4954 // let cursor = cursor.to_point(&buffer);
4955 // Selection {
4956 // id,
4957 // start: cursor,
4958 // end: cursor,
4959 // reversed: false,
4960 // goal: SelectionGoal::None,
4961 // }
4962 // })
4963 // .collect();
4964
4965 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4966 // s.select(new_selections);
4967 // });
4968 // });
4969 // }
4970
4971 // pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
4972 // let mut row_ranges = Vec::<Range<u32>>::new();
4973 // for selection in self.selections.all::<Point>(cx) {
4974 // let start = selection.start.row;
4975 // let end = if selection.start.row == selection.end.row {
4976 // selection.start.row + 1
4977 // } else {
4978 // selection.end.row
4979 // };
4980
4981 // if let Some(last_row_range) = row_ranges.last_mut() {
4982 // if start <= last_row_range.end {
4983 // last_row_range.end = end;
4984 // continue;
4985 // }
4986 // }
4987 // row_ranges.push(start..end);
4988 // }
4989
4990 // let snapshot = self.buffer.read(cx).snapshot(cx);
4991 // let mut cursor_positions = Vec::new();
4992 // for row_range in &row_ranges {
4993 // let anchor = snapshot.anchor_before(Point::new(
4994 // row_range.end - 1,
4995 // snapshot.line_len(row_range.end - 1),
4996 // ));
4997 // cursor_positions.push(anchor.clone()..anchor);
4998 // }
4999
5000 // self.transact(cx, |this, cx| {
5001 // for row_range in row_ranges.into_iter().rev() {
5002 // for row in row_range.rev() {
5003 // let end_of_line = Point::new(row, snapshot.line_len(row));
5004 // let indent = snapshot.indent_size_for_line(row + 1);
5005 // let start_of_next_line = Point::new(row + 1, indent.len);
5006
5007 // let replace = if snapshot.line_len(row + 1) > indent.len {
5008 // " "
5009 // } else {
5010 // ""
5011 // };
5012
5013 // this.buffer.update(cx, |buffer, cx| {
5014 // buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
5015 // });
5016 // }
5017 // }
5018
5019 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5020 // s.select_anchor_ranges(cursor_positions)
5021 // });
5022 // });
5023 // }
5024
5025 // pub fn sort_lines_case_sensitive(
5026 // &mut self,
5027 // _: &SortLinesCaseSensitive,
5028 // cx: &mut ViewContext<Self>,
5029 // ) {
5030 // self.manipulate_lines(cx, |lines| lines.sort())
5031 // }
5032
5033 // pub fn sort_lines_case_insensitive(
5034 // &mut self,
5035 // _: &SortLinesCaseInsensitive,
5036 // cx: &mut ViewContext<Self>,
5037 // ) {
5038 // self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
5039 // }
5040
5041 // pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
5042 // self.manipulate_lines(cx, |lines| lines.reverse())
5043 // }
5044
5045 // pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
5046 // self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
5047 // }
5048
5049 // fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
5050 // where
5051 // Fn: FnMut(&mut [&str]),
5052 // {
5053 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5054 // let buffer = self.buffer.read(cx).snapshot(cx);
5055
5056 // let mut edits = Vec::new();
5057
5058 // let selections = self.selections.all::<Point>(cx);
5059 // let mut selections = selections.iter().peekable();
5060 // let mut contiguous_row_selections = Vec::new();
5061 // let mut new_selections = Vec::new();
5062
5063 // while let Some(selection) = selections.next() {
5064 // let (start_row, end_row) = consume_contiguous_rows(
5065 // &mut contiguous_row_selections,
5066 // selection,
5067 // &display_map,
5068 // &mut selections,
5069 // );
5070
5071 // let start_point = Point::new(start_row, 0);
5072 // let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
5073 // let text = buffer
5074 // .text_for_range(start_point..end_point)
5075 // .collect::<String>();
5076 // let mut lines = text.split("\n").collect_vec();
5077
5078 // let lines_len = lines.len();
5079 // callback(&mut lines);
5080
5081 // // This is a current limitation with selections.
5082 // // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections.
5083 // debug_assert!(
5084 // lines.len() == lines_len,
5085 // "callback should not change the number of lines"
5086 // );
5087
5088 // edits.push((start_point..end_point, lines.join("\n")));
5089 // let start_anchor = buffer.anchor_after(start_point);
5090 // let end_anchor = buffer.anchor_before(end_point);
5091
5092 // // Make selection and push
5093 // new_selections.push(Selection {
5094 // id: selection.id,
5095 // start: start_anchor.to_offset(&buffer),
5096 // end: end_anchor.to_offset(&buffer),
5097 // goal: SelectionGoal::None,
5098 // reversed: selection.reversed,
5099 // });
5100 // }
5101
5102 // self.transact(cx, |this, cx| {
5103 // this.buffer.update(cx, |buffer, cx| {
5104 // buffer.edit(edits, None, cx);
5105 // });
5106
5107 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5108 // s.select(new_selections);
5109 // });
5110
5111 // this.request_autoscroll(Autoscroll::fit(), cx);
5112 // });
5113 // }
5114
5115 // pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
5116 // self.manipulate_text(cx, |text| text.to_uppercase())
5117 // }
5118
5119 // pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
5120 // self.manipulate_text(cx, |text| text.to_lowercase())
5121 // }
5122
5123 // pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
5124 // self.manipulate_text(cx, |text| {
5125 // // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
5126 // // https://github.com/rutrum/convert-case/issues/16
5127 // text.split("\n")
5128 // .map(|line| line.to_case(Case::Title))
5129 // .join("\n")
5130 // })
5131 // }
5132
5133 // pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
5134 // self.manipulate_text(cx, |text| text.to_case(Case::Snake))
5135 // }
5136
5137 // pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
5138 // self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
5139 // }
5140
5141 // pub fn convert_to_upper_camel_case(
5142 // &mut self,
5143 // _: &ConvertToUpperCamelCase,
5144 // cx: &mut ViewContext<Self>,
5145 // ) {
5146 // self.manipulate_text(cx, |text| {
5147 // // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
5148 // // https://github.com/rutrum/convert-case/issues/16
5149 // text.split("\n")
5150 // .map(|line| line.to_case(Case::UpperCamel))
5151 // .join("\n")
5152 // })
5153 // }
5154
5155 // pub fn convert_to_lower_camel_case(
5156 // &mut self,
5157 // _: &ConvertToLowerCamelCase,
5158 // cx: &mut ViewContext<Self>,
5159 // ) {
5160 // self.manipulate_text(cx, |text| text.to_case(Case::Camel))
5161 // }
5162
5163 // fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
5164 // where
5165 // Fn: FnMut(&str) -> String,
5166 // {
5167 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5168 // let buffer = self.buffer.read(cx).snapshot(cx);
5169
5170 // let mut new_selections = Vec::new();
5171 // let mut edits = Vec::new();
5172 // let mut selection_adjustment = 0i32;
5173
5174 // for selection in self.selections.all::<usize>(cx) {
5175 // let selection_is_empty = selection.is_empty();
5176
5177 // let (start, end) = if selection_is_empty {
5178 // let word_range = movement::surrounding_word(
5179 // &display_map,
5180 // selection.start.to_display_point(&display_map),
5181 // );
5182 // let start = word_range.start.to_offset(&display_map, Bias::Left);
5183 // let end = word_range.end.to_offset(&display_map, Bias::Left);
5184 // (start, end)
5185 // } else {
5186 // (selection.start, selection.end)
5187 // };
5188
5189 // let text = buffer.text_for_range(start..end).collect::<String>();
5190 // let old_length = text.len() as i32;
5191 // let text = callback(&text);
5192
5193 // new_selections.push(Selection {
5194 // start: (start as i32 - selection_adjustment) as usize,
5195 // end: ((start + text.len()) as i32 - selection_adjustment) as usize,
5196 // goal: SelectionGoal::None,
5197 // ..selection
5198 // });
5199
5200 // selection_adjustment += old_length - text.len() as i32;
5201
5202 // edits.push((start..end, text));
5203 // }
5204
5205 // self.transact(cx, |this, cx| {
5206 // this.buffer.update(cx, |buffer, cx| {
5207 // buffer.edit(edits, None, cx);
5208 // });
5209
5210 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5211 // s.select(new_selections);
5212 // });
5213
5214 // this.request_autoscroll(Autoscroll::fit(), cx);
5215 // });
5216 // }
5217
5218 // pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
5219 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5220 // let buffer = &display_map.buffer_snapshot;
5221 // let selections = self.selections.all::<Point>(cx);
5222
5223 // let mut edits = Vec::new();
5224 // let mut selections_iter = selections.iter().peekable();
5225 // while let Some(selection) = selections_iter.next() {
5226 // // Avoid duplicating the same lines twice.
5227 // let mut rows = selection.spanned_rows(false, &display_map);
5228
5229 // while let Some(next_selection) = selections_iter.peek() {
5230 // let next_rows = next_selection.spanned_rows(false, &display_map);
5231 // if next_rows.start < rows.end {
5232 // rows.end = next_rows.end;
5233 // selections_iter.next().unwrap();
5234 // } else {
5235 // break;
5236 // }
5237 // }
5238
5239 // // Copy the text from the selected row region and splice it at the start of the region.
5240 // let start = Point::new(rows.start, 0);
5241 // let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
5242 // let text = buffer
5243 // .text_for_range(start..end)
5244 // .chain(Some("\n"))
5245 // .collect::<String>();
5246 // edits.push((start..start, text));
5247 // }
5248
5249 // self.transact(cx, |this, cx| {
5250 // this.buffer.update(cx, |buffer, cx| {
5251 // buffer.edit(edits, None, cx);
5252 // });
5253
5254 // this.request_autoscroll(Autoscroll::fit(), cx);
5255 // });
5256 // }
5257
5258 // pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
5259 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5260 // let buffer = self.buffer.read(cx).snapshot(cx);
5261
5262 // let mut edits = Vec::new();
5263 // let mut unfold_ranges = Vec::new();
5264 // let mut refold_ranges = Vec::new();
5265
5266 // let selections = self.selections.all::<Point>(cx);
5267 // let mut selections = selections.iter().peekable();
5268 // let mut contiguous_row_selections = Vec::new();
5269 // let mut new_selections = Vec::new();
5270
5271 // while let Some(selection) = selections.next() {
5272 // // Find all the selections that span a contiguous row range
5273 // let (start_row, end_row) = consume_contiguous_rows(
5274 // &mut contiguous_row_selections,
5275 // selection,
5276 // &display_map,
5277 // &mut selections,
5278 // );
5279
5280 // // Move the text spanned by the row range to be before the line preceding the row range
5281 // if start_row > 0 {
5282 // let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
5283 // ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
5284 // let insertion_point = display_map
5285 // .prev_line_boundary(Point::new(start_row - 1, 0))
5286 // .0;
5287
5288 // // Don't move lines across excerpts
5289 // if buffer
5290 // .excerpt_boundaries_in_range((
5291 // Bound::Excluded(insertion_point),
5292 // Bound::Included(range_to_move.end),
5293 // ))
5294 // .next()
5295 // .is_none()
5296 // {
5297 // let text = buffer
5298 // .text_for_range(range_to_move.clone())
5299 // .flat_map(|s| s.chars())
5300 // .skip(1)
5301 // .chain(['\n'])
5302 // .collect::<String>();
5303
5304 // edits.push((
5305 // buffer.anchor_after(range_to_move.start)
5306 // ..buffer.anchor_before(range_to_move.end),
5307 // String::new(),
5308 // ));
5309 // let insertion_anchor = buffer.anchor_after(insertion_point);
5310 // edits.push((insertion_anchor..insertion_anchor, text));
5311
5312 // let row_delta = range_to_move.start.row - insertion_point.row + 1;
5313
5314 // // Move selections up
5315 // new_selections.extend(contiguous_row_selections.drain(..).map(
5316 // |mut selection| {
5317 // selection.start.row -= row_delta;
5318 // selection.end.row -= row_delta;
5319 // selection
5320 // },
5321 // ));
5322
5323 // // Move folds up
5324 // unfold_ranges.push(range_to_move.clone());
5325 // for fold in display_map.folds_in_range(
5326 // buffer.anchor_before(range_to_move.start)
5327 // ..buffer.anchor_after(range_to_move.end),
5328 // ) {
5329 // let mut start = fold.start.to_point(&buffer);
5330 // let mut end = fold.end.to_point(&buffer);
5331 // start.row -= row_delta;
5332 // end.row -= row_delta;
5333 // refold_ranges.push(start..end);
5334 // }
5335 // }
5336 // }
5337
5338 // // If we didn't move line(s), preserve the existing selections
5339 // new_selections.append(&mut contiguous_row_selections);
5340 // }
5341
5342 // self.transact(cx, |this, cx| {
5343 // this.unfold_ranges(unfold_ranges, true, true, cx);
5344 // this.buffer.update(cx, |buffer, cx| {
5345 // for (range, text) in edits {
5346 // buffer.edit([(range, text)], None, cx);
5347 // }
5348 // });
5349 // this.fold_ranges(refold_ranges, true, cx);
5350 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5351 // s.select(new_selections);
5352 // })
5353 // });
5354 // }
5355
5356 // pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
5357 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5358 // let buffer = self.buffer.read(cx).snapshot(cx);
5359
5360 // let mut edits = Vec::new();
5361 // let mut unfold_ranges = Vec::new();
5362 // let mut refold_ranges = Vec::new();
5363
5364 // let selections = self.selections.all::<Point>(cx);
5365 // let mut selections = selections.iter().peekable();
5366 // let mut contiguous_row_selections = Vec::new();
5367 // let mut new_selections = Vec::new();
5368
5369 // while let Some(selection) = selections.next() {
5370 // // Find all the selections that span a contiguous row range
5371 // let (start_row, end_row) = consume_contiguous_rows(
5372 // &mut contiguous_row_selections,
5373 // selection,
5374 // &display_map,
5375 // &mut selections,
5376 // );
5377
5378 // // Move the text spanned by the row range to be after the last line of the row range
5379 // if end_row <= buffer.max_point().row {
5380 // let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
5381 // let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
5382
5383 // // Don't move lines across excerpt boundaries
5384 // if buffer
5385 // .excerpt_boundaries_in_range((
5386 // Bound::Excluded(range_to_move.start),
5387 // Bound::Included(insertion_point),
5388 // ))
5389 // .next()
5390 // .is_none()
5391 // {
5392 // let mut text = String::from("\n");
5393 // text.extend(buffer.text_for_range(range_to_move.clone()));
5394 // text.pop(); // Drop trailing newline
5395 // edits.push((
5396 // buffer.anchor_after(range_to_move.start)
5397 // ..buffer.anchor_before(range_to_move.end),
5398 // String::new(),
5399 // ));
5400 // let insertion_anchor = buffer.anchor_after(insertion_point);
5401 // edits.push((insertion_anchor..insertion_anchor, text));
5402
5403 // let row_delta = insertion_point.row - range_to_move.end.row + 1;
5404
5405 // // Move selections down
5406 // new_selections.extend(contiguous_row_selections.drain(..).map(
5407 // |mut selection| {
5408 // selection.start.row += row_delta;
5409 // selection.end.row += row_delta;
5410 // selection
5411 // },
5412 // ));
5413
5414 // // Move folds down
5415 // unfold_ranges.push(range_to_move.clone());
5416 // for fold in display_map.folds_in_range(
5417 // buffer.anchor_before(range_to_move.start)
5418 // ..buffer.anchor_after(range_to_move.end),
5419 // ) {
5420 // let mut start = fold.start.to_point(&buffer);
5421 // let mut end = fold.end.to_point(&buffer);
5422 // start.row += row_delta;
5423 // end.row += row_delta;
5424 // refold_ranges.push(start..end);
5425 // }
5426 // }
5427 // }
5428
5429 // // If we didn't move line(s), preserve the existing selections
5430 // new_selections.append(&mut contiguous_row_selections);
5431 // }
5432
5433 // self.transact(cx, |this, cx| {
5434 // this.unfold_ranges(unfold_ranges, true, true, cx);
5435 // this.buffer.update(cx, |buffer, cx| {
5436 // for (range, text) in edits {
5437 // buffer.edit([(range, text)], None, cx);
5438 // }
5439 // });
5440 // this.fold_ranges(refold_ranges, true, cx);
5441 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
5442 // });
5443 // }
5444
5445 // pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
5446 // let text_layout_details = &self.text_layout_details(cx);
5447 // self.transact(cx, |this, cx| {
5448 // let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5449 // let mut edits: Vec<(Range<usize>, String)> = Default::default();
5450 // let line_mode = s.line_mode;
5451 // s.move_with(|display_map, selection| {
5452 // if !selection.is_empty() || line_mode {
5453 // return;
5454 // }
5455
5456 // let mut head = selection.head();
5457 // let mut transpose_offset = head.to_offset(display_map, Bias::Right);
5458 // if head.column() == display_map.line_len(head.row()) {
5459 // transpose_offset = display_map
5460 // .buffer_snapshot
5461 // .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
5462 // }
5463
5464 // if transpose_offset == 0 {
5465 // return;
5466 // }
5467
5468 // *head.column_mut() += 1;
5469 // head = display_map.clip_point(head, Bias::Right);
5470 // let goal = SelectionGoal::HorizontalPosition(
5471 // display_map.x_for_point(head, &text_layout_details),
5472 // );
5473 // selection.collapse_to(head, goal);
5474
5475 // let transpose_start = display_map
5476 // .buffer_snapshot
5477 // .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
5478 // if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
5479 // let transpose_end = display_map
5480 // .buffer_snapshot
5481 // .clip_offset(transpose_offset + 1, Bias::Right);
5482 // if let Some(ch) =
5483 // display_map.buffer_snapshot.chars_at(transpose_start).next()
5484 // {
5485 // edits.push((transpose_start..transpose_offset, String::new()));
5486 // edits.push((transpose_end..transpose_end, ch.to_string()));
5487 // }
5488 // }
5489 // });
5490 // edits
5491 // });
5492 // this.buffer
5493 // .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
5494 // let selections = this.selections.all::<usize>(cx);
5495 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5496 // s.select(selections);
5497 // });
5498 // });
5499 // }
5500
5501 // pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
5502 // let mut text = String::new();
5503 // let buffer = self.buffer.read(cx).snapshot(cx);
5504 // let mut selections = self.selections.all::<Point>(cx);
5505 // let mut clipboard_selections = Vec::with_capacity(selections.len());
5506 // {
5507 // let max_point = buffer.max_point();
5508 // let mut is_first = true;
5509 // for selection in &mut selections {
5510 // let is_entire_line = selection.is_empty() || self.selections.line_mode;
5511 // if is_entire_line {
5512 // selection.start = Point::new(selection.start.row, 0);
5513 // selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
5514 // selection.goal = SelectionGoal::None;
5515 // }
5516 // if is_first {
5517 // is_first = false;
5518 // } else {
5519 // text += "\n";
5520 // }
5521 // let mut len = 0;
5522 // for chunk in buffer.text_for_range(selection.start..selection.end) {
5523 // text.push_str(chunk);
5524 // len += chunk.len();
5525 // }
5526 // clipboard_selections.push(ClipboardSelection {
5527 // len,
5528 // is_entire_line,
5529 // first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
5530 // });
5531 // }
5532 // }
5533
5534 // self.transact(cx, |this, cx| {
5535 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5536 // s.select(selections);
5537 // });
5538 // this.insert("", cx);
5539 // cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
5540 // });
5541 // }
5542
5543 // pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
5544 // let selections = self.selections.all::<Point>(cx);
5545 // let buffer = self.buffer.read(cx).read(cx);
5546 // let mut text = String::new();
5547
5548 // let mut clipboard_selections = Vec::with_capacity(selections.len());
5549 // {
5550 // let max_point = buffer.max_point();
5551 // let mut is_first = true;
5552 // for selection in selections.iter() {
5553 // let mut start = selection.start;
5554 // let mut end = selection.end;
5555 // let is_entire_line = selection.is_empty() || self.selections.line_mode;
5556 // if is_entire_line {
5557 // start = Point::new(start.row, 0);
5558 // end = cmp::min(max_point, Point::new(end.row + 1, 0));
5559 // }
5560 // if is_first {
5561 // is_first = false;
5562 // } else {
5563 // text += "\n";
5564 // }
5565 // let mut len = 0;
5566 // for chunk in buffer.text_for_range(start..end) {
5567 // text.push_str(chunk);
5568 // len += chunk.len();
5569 // }
5570 // clipboard_selections.push(ClipboardSelection {
5571 // len,
5572 // is_entire_line,
5573 // first_line_indent: buffer.indent_size_for_line(start.row).len,
5574 // });
5575 // }
5576 // }
5577
5578 // cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
5579 // }
5580
5581 // pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
5582 // self.transact(cx, |this, cx| {
5583 // if let Some(item) = cx.read_from_clipboard() {
5584 // let clipboard_text = Cow::Borrowed(item.text());
5585 // if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
5586 // let old_selections = this.selections.all::<usize>(cx);
5587 // let all_selections_were_entire_line =
5588 // clipboard_selections.iter().all(|s| s.is_entire_line);
5589 // let first_selection_indent_column =
5590 // clipboard_selections.first().map(|s| s.first_line_indent);
5591 // if clipboard_selections.len() != old_selections.len() {
5592 // clipboard_selections.drain(..);
5593 // }
5594
5595 // this.buffer.update(cx, |buffer, cx| {
5596 // let snapshot = buffer.read(cx);
5597 // let mut start_offset = 0;
5598 // let mut edits = Vec::new();
5599 // let mut original_indent_columns = Vec::new();
5600 // let line_mode = this.selections.line_mode;
5601 // for (ix, selection) in old_selections.iter().enumerate() {
5602 // let to_insert;
5603 // let entire_line;
5604 // let original_indent_column;
5605 // if let Some(clipboard_selection) = clipboard_selections.get(ix) {
5606 // let end_offset = start_offset + clipboard_selection.len;
5607 // to_insert = &clipboard_text[start_offset..end_offset];
5608 // entire_line = clipboard_selection.is_entire_line;
5609 // start_offset = end_offset + 1;
5610 // original_indent_column =
5611 // Some(clipboard_selection.first_line_indent);
5612 // } else {
5613 // to_insert = clipboard_text.as_str();
5614 // entire_line = all_selections_were_entire_line;
5615 // original_indent_column = first_selection_indent_column
5616 // }
5617
5618 // // If the corresponding selection was empty when this slice of the
5619 // // clipboard text was written, then the entire line containing the
5620 // // selection was copied. If this selection is also currently empty,
5621 // // then paste the line before the current line of the buffer.
5622 // let range = if selection.is_empty() && !line_mode && entire_line {
5623 // let column = selection.start.to_point(&snapshot).column as usize;
5624 // let line_start = selection.start - column;
5625 // line_start..line_start
5626 // } else {
5627 // selection.range()
5628 // };
5629
5630 // edits.push((range, to_insert));
5631 // original_indent_columns.extend(original_indent_column);
5632 // }
5633 // drop(snapshot);
5634
5635 // buffer.edit(
5636 // edits,
5637 // Some(AutoindentMode::Block {
5638 // original_indent_columns,
5639 // }),
5640 // cx,
5641 // );
5642 // });
5643
5644 // let selections = this.selections.all::<usize>(cx);
5645 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
5646 // } else {
5647 // this.insert(&clipboard_text, cx);
5648 // }
5649 // }
5650 // });
5651 // }
5652
5653 // pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
5654 // if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
5655 // if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
5656 // self.change_selections(None, cx, |s| {
5657 // s.select_anchors(selections.to_vec());
5658 // });
5659 // }
5660 // self.request_autoscroll(Autoscroll::fit(), cx);
5661 // self.unmark_text(cx);
5662 // self.refresh_copilot_suggestions(true, cx);
5663 // cx.emit(Event::Edited);
5664 // }
5665 // }
5666
5667 // pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
5668 // if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
5669 // if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
5670 // {
5671 // self.change_selections(None, cx, |s| {
5672 // s.select_anchors(selections.to_vec());
5673 // });
5674 // }
5675 // self.request_autoscroll(Autoscroll::fit(), cx);
5676 // self.unmark_text(cx);
5677 // self.refresh_copilot_suggestions(true, cx);
5678 // cx.emit(Event::Edited);
5679 // }
5680 // }
5681
5682 // pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
5683 // self.buffer
5684 // .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
5685 // }
5686
5687 // pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
5688 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5689 // let line_mode = s.line_mode;
5690 // s.move_with(|map, selection| {
5691 // let cursor = if selection.is_empty() && !line_mode {
5692 // movement::left(map, selection.start)
5693 // } else {
5694 // selection.start
5695 // };
5696 // selection.collapse_to(cursor, SelectionGoal::None);
5697 // });
5698 // })
5699 // }
5700
5701 // pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
5702 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5703 // s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
5704 // })
5705 // }
5706
5707 // pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
5708 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5709 // let line_mode = s.line_mode;
5710 // s.move_with(|map, selection| {
5711 // let cursor = if selection.is_empty() && !line_mode {
5712 // movement::right(map, selection.end)
5713 // } else {
5714 // selection.end
5715 // };
5716 // selection.collapse_to(cursor, SelectionGoal::None)
5717 // });
5718 // })
5719 // }
5720
5721 // pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
5722 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5723 // s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
5724 // })
5725 // }
5726
5727 // pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
5728 // if self.take_rename(true, cx).is_some() {
5729 // return;
5730 // }
5731
5732 // if matches!(self.mode, EditorMode::SingleLine) {
5733 // cx.propagate_action();
5734 // return;
5735 // }
5736
5737 // let text_layout_details = &self.text_layout_details(cx);
5738
5739 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5740 // let line_mode = s.line_mode;
5741 // s.move_with(|map, selection| {
5742 // if !selection.is_empty() && !line_mode {
5743 // selection.goal = SelectionGoal::None;
5744 // }
5745 // let (cursor, goal) = movement::up(
5746 // map,
5747 // selection.start,
5748 // selection.goal,
5749 // false,
5750 // &text_layout_details,
5751 // );
5752 // selection.collapse_to(cursor, goal);
5753 // });
5754 // })
5755 // }
5756
5757 // pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
5758 // if self.take_rename(true, cx).is_some() {
5759 // return;
5760 // }
5761
5762 // if matches!(self.mode, EditorMode::SingleLine) {
5763 // cx.propagate_action();
5764 // return;
5765 // }
5766
5767 // let row_count = if let Some(row_count) = self.visible_line_count() {
5768 // row_count as u32 - 1
5769 // } else {
5770 // return;
5771 // };
5772
5773 // let autoscroll = if action.center_cursor {
5774 // Autoscroll::center()
5775 // } else {
5776 // Autoscroll::fit()
5777 // };
5778
5779 // let text_layout_details = &self.text_layout_details(cx);
5780
5781 // self.change_selections(Some(autoscroll), cx, |s| {
5782 // let line_mode = s.line_mode;
5783 // s.move_with(|map, selection| {
5784 // if !selection.is_empty() && !line_mode {
5785 // selection.goal = SelectionGoal::None;
5786 // }
5787 // let (cursor, goal) = movement::up_by_rows(
5788 // map,
5789 // selection.end,
5790 // row_count,
5791 // selection.goal,
5792 // false,
5793 // &text_layout_details,
5794 // );
5795 // selection.collapse_to(cursor, goal);
5796 // });
5797 // });
5798 // }
5799
5800 // pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
5801 // let text_layout_details = &self.text_layout_details(cx);
5802 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5803 // s.move_heads_with(|map, head, goal| {
5804 // movement::up(map, head, goal, false, &text_layout_details)
5805 // })
5806 // })
5807 // }
5808
5809 // pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
5810 // self.take_rename(true, cx);
5811
5812 // if self.mode == EditorMode::SingleLine {
5813 // cx.propagate_action();
5814 // return;
5815 // }
5816
5817 // let text_layout_details = &self.text_layout_details(cx);
5818 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5819 // let line_mode = s.line_mode;
5820 // s.move_with(|map, selection| {
5821 // if !selection.is_empty() && !line_mode {
5822 // selection.goal = SelectionGoal::None;
5823 // }
5824 // let (cursor, goal) = movement::down(
5825 // map,
5826 // selection.end,
5827 // selection.goal,
5828 // false,
5829 // &text_layout_details,
5830 // );
5831 // selection.collapse_to(cursor, goal);
5832 // });
5833 // });
5834 // }
5835
5836 // pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
5837 // if self.take_rename(true, cx).is_some() {
5838 // return;
5839 // }
5840
5841 // if self
5842 // .context_menu
5843 // .write()
5844 // .as_mut()
5845 // .map(|menu| menu.select_last(self.project.as_ref(), cx))
5846 // .unwrap_or(false)
5847 // {
5848 // return;
5849 // }
5850
5851 // if matches!(self.mode, EditorMode::SingleLine) {
5852 // cx.propagate_action();
5853 // return;
5854 // }
5855
5856 // let row_count = if let Some(row_count) = self.visible_line_count() {
5857 // row_count as u32 - 1
5858 // } else {
5859 // return;
5860 // };
5861
5862 // let autoscroll = if action.center_cursor {
5863 // Autoscroll::center()
5864 // } else {
5865 // Autoscroll::fit()
5866 // };
5867
5868 // let text_layout_details = &self.text_layout_details(cx);
5869 // self.change_selections(Some(autoscroll), cx, |s| {
5870 // let line_mode = s.line_mode;
5871 // s.move_with(|map, selection| {
5872 // if !selection.is_empty() && !line_mode {
5873 // selection.goal = SelectionGoal::None;
5874 // }
5875 // let (cursor, goal) = movement::down_by_rows(
5876 // map,
5877 // selection.end,
5878 // row_count,
5879 // selection.goal,
5880 // false,
5881 // &text_layout_details,
5882 // );
5883 // selection.collapse_to(cursor, goal);
5884 // });
5885 // });
5886 // }
5887
5888 // pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
5889 // let text_layout_details = &self.text_layout_details(cx);
5890 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5891 // s.move_heads_with(|map, head, goal| {
5892 // movement::down(map, head, goal, false, &text_layout_details)
5893 // })
5894 // });
5895 // }
5896
5897 // pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
5898 // if let Some(context_menu) = self.context_menu.write().as_mut() {
5899 // context_menu.select_first(self.project.as_ref(), cx);
5900 // }
5901 // }
5902
5903 // pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
5904 // if let Some(context_menu) = self.context_menu.write().as_mut() {
5905 // context_menu.select_prev(self.project.as_ref(), cx);
5906 // }
5907 // }
5908
5909 // pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
5910 // if let Some(context_menu) = self.context_menu.write().as_mut() {
5911 // context_menu.select_next(self.project.as_ref(), cx);
5912 // }
5913 // }
5914
5915 // pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
5916 // if let Some(context_menu) = self.context_menu.write().as_mut() {
5917 // context_menu.select_last(self.project.as_ref(), cx);
5918 // }
5919 // }
5920
5921 // pub fn move_to_previous_word_start(
5922 // &mut self,
5923 // _: &MoveToPreviousWordStart,
5924 // cx: &mut ViewContext<Self>,
5925 // ) {
5926 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5927 // s.move_cursors_with(|map, head, _| {
5928 // (
5929 // movement::previous_word_start(map, head),
5930 // SelectionGoal::None,
5931 // )
5932 // });
5933 // })
5934 // }
5935
5936 // pub fn move_to_previous_subword_start(
5937 // &mut self,
5938 // _: &MoveToPreviousSubwordStart,
5939 // cx: &mut ViewContext<Self>,
5940 // ) {
5941 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5942 // s.move_cursors_with(|map, head, _| {
5943 // (
5944 // movement::previous_subword_start(map, head),
5945 // SelectionGoal::None,
5946 // )
5947 // });
5948 // })
5949 // }
5950
5951 // pub fn select_to_previous_word_start(
5952 // &mut self,
5953 // _: &SelectToPreviousWordStart,
5954 // cx: &mut ViewContext<Self>,
5955 // ) {
5956 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5957 // s.move_heads_with(|map, head, _| {
5958 // (
5959 // movement::previous_word_start(map, head),
5960 // SelectionGoal::None,
5961 // )
5962 // });
5963 // })
5964 // }
5965
5966 // pub fn select_to_previous_subword_start(
5967 // &mut self,
5968 // _: &SelectToPreviousSubwordStart,
5969 // cx: &mut ViewContext<Self>,
5970 // ) {
5971 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5972 // s.move_heads_with(|map, head, _| {
5973 // (
5974 // movement::previous_subword_start(map, head),
5975 // SelectionGoal::None,
5976 // )
5977 // });
5978 // })
5979 // }
5980
5981 // pub fn delete_to_previous_word_start(
5982 // &mut self,
5983 // _: &DeleteToPreviousWordStart,
5984 // cx: &mut ViewContext<Self>,
5985 // ) {
5986 // self.transact(cx, |this, cx| {
5987 // this.select_autoclose_pair(cx);
5988 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5989 // let line_mode = s.line_mode;
5990 // s.move_with(|map, selection| {
5991 // if selection.is_empty() && !line_mode {
5992 // let cursor = movement::previous_word_start(map, selection.head());
5993 // selection.set_head(cursor, SelectionGoal::None);
5994 // }
5995 // });
5996 // });
5997 // this.insert("", cx);
5998 // });
5999 // }
6000
6001 // pub fn delete_to_previous_subword_start(
6002 // &mut self,
6003 // _: &DeleteToPreviousSubwordStart,
6004 // cx: &mut ViewContext<Self>,
6005 // ) {
6006 // self.transact(cx, |this, cx| {
6007 // this.select_autoclose_pair(cx);
6008 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
6009 // let line_mode = s.line_mode;
6010 // s.move_with(|map, selection| {
6011 // if selection.is_empty() && !line_mode {
6012 // let cursor = movement::previous_subword_start(map, selection.head());
6013 // selection.set_head(cursor, SelectionGoal::None);
6014 // }
6015 // });
6016 // });
6017 // this.insert("", cx);
6018 // });
6019 // }
6020
6021 // pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
6022 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6023 // s.move_cursors_with(|map, head, _| {
6024 // (movement::next_word_end(map, head), SelectionGoal::None)
6025 // });
6026 // })
6027 // }
6028
6029 // pub fn move_to_next_subword_end(
6030 // &mut self,
6031 // _: &MoveToNextSubwordEnd,
6032 // cx: &mut ViewContext<Self>,
6033 // ) {
6034 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6035 // s.move_cursors_with(|map, head, _| {
6036 // (movement::next_subword_end(map, head), SelectionGoal::None)
6037 // });
6038 // })
6039 // }
6040
6041 // pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
6042 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6043 // s.move_heads_with(|map, head, _| {
6044 // (movement::next_word_end(map, head), SelectionGoal::None)
6045 // });
6046 // })
6047 // }
6048
6049 // pub fn select_to_next_subword_end(
6050 // &mut self,
6051 // _: &SelectToNextSubwordEnd,
6052 // cx: &mut ViewContext<Self>,
6053 // ) {
6054 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6055 // s.move_heads_with(|map, head, _| {
6056 // (movement::next_subword_end(map, head), SelectionGoal::None)
6057 // });
6058 // })
6059 // }
6060
6061 // pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
6062 // self.transact(cx, |this, cx| {
6063 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
6064 // let line_mode = s.line_mode;
6065 // s.move_with(|map, selection| {
6066 // if selection.is_empty() && !line_mode {
6067 // let cursor = movement::next_word_end(map, selection.head());
6068 // selection.set_head(cursor, SelectionGoal::None);
6069 // }
6070 // });
6071 // });
6072 // this.insert("", cx);
6073 // });
6074 // }
6075
6076 // pub fn delete_to_next_subword_end(
6077 // &mut self,
6078 // _: &DeleteToNextSubwordEnd,
6079 // cx: &mut ViewContext<Self>,
6080 // ) {
6081 // self.transact(cx, |this, cx| {
6082 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
6083 // s.move_with(|map, selection| {
6084 // if selection.is_empty() {
6085 // let cursor = movement::next_subword_end(map, selection.head());
6086 // selection.set_head(cursor, SelectionGoal::None);
6087 // }
6088 // });
6089 // });
6090 // this.insert("", cx);
6091 // });
6092 // }
6093
6094 // pub fn move_to_beginning_of_line(
6095 // &mut self,
6096 // _: &MoveToBeginningOfLine,
6097 // cx: &mut ViewContext<Self>,
6098 // ) {
6099 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6100 // s.move_cursors_with(|map, head, _| {
6101 // (
6102 // movement::indented_line_beginning(map, head, true),
6103 // SelectionGoal::None,
6104 // )
6105 // });
6106 // })
6107 // }
6108
6109 // pub fn select_to_beginning_of_line(
6110 // &mut self,
6111 // action: &SelectToBeginningOfLine,
6112 // cx: &mut ViewContext<Self>,
6113 // ) {
6114 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6115 // s.move_heads_with(|map, head, _| {
6116 // (
6117 // movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
6118 // SelectionGoal::None,
6119 // )
6120 // });
6121 // });
6122 // }
6123
6124 // pub fn delete_to_beginning_of_line(
6125 // &mut self,
6126 // _: &DeleteToBeginningOfLine,
6127 // cx: &mut ViewContext<Self>,
6128 // ) {
6129 // self.transact(cx, |this, cx| {
6130 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
6131 // s.move_with(|_, selection| {
6132 // selection.reversed = true;
6133 // });
6134 // });
6135
6136 // this.select_to_beginning_of_line(
6137 // &SelectToBeginningOfLine {
6138 // stop_at_soft_wraps: false,
6139 // },
6140 // cx,
6141 // );
6142 // this.backspace(&Backspace, cx);
6143 // });
6144 // }
6145
6146 // pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
6147 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6148 // s.move_cursors_with(|map, head, _| {
6149 // (movement::line_end(map, head, true), SelectionGoal::None)
6150 // });
6151 // })
6152 // }
6153
6154 // pub fn select_to_end_of_line(
6155 // &mut self,
6156 // action: &SelectToEndOfLine,
6157 // cx: &mut ViewContext<Self>,
6158 // ) {
6159 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6160 // s.move_heads_with(|map, head, _| {
6161 // (
6162 // movement::line_end(map, head, action.stop_at_soft_wraps),
6163 // SelectionGoal::None,
6164 // )
6165 // });
6166 // })
6167 // }
6168
6169 // pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
6170 // self.transact(cx, |this, cx| {
6171 // this.select_to_end_of_line(
6172 // &SelectToEndOfLine {
6173 // stop_at_soft_wraps: false,
6174 // },
6175 // cx,
6176 // );
6177 // this.delete(&Delete, cx);
6178 // });
6179 // }
6180
6181 // pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
6182 // self.transact(cx, |this, cx| {
6183 // this.select_to_end_of_line(
6184 // &SelectToEndOfLine {
6185 // stop_at_soft_wraps: false,
6186 // },
6187 // cx,
6188 // );
6189 // this.cut(&Cut, cx);
6190 // });
6191 // }
6192
6193 // pub fn move_to_start_of_paragraph(
6194 // &mut self,
6195 // _: &MoveToStartOfParagraph,
6196 // cx: &mut ViewContext<Self>,
6197 // ) {
6198 // if matches!(self.mode, EditorMode::SingleLine) {
6199 // cx.propagate_action();
6200 // return;
6201 // }
6202
6203 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6204 // s.move_with(|map, selection| {
6205 // selection.collapse_to(
6206 // movement::start_of_paragraph(map, selection.head(), 1),
6207 // SelectionGoal::None,
6208 // )
6209 // });
6210 // })
6211 // }
6212
6213 // pub fn move_to_end_of_paragraph(
6214 // &mut self,
6215 // _: &MoveToEndOfParagraph,
6216 // cx: &mut ViewContext<Self>,
6217 // ) {
6218 // if matches!(self.mode, EditorMode::SingleLine) {
6219 // cx.propagate_action();
6220 // return;
6221 // }
6222
6223 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6224 // s.move_with(|map, selection| {
6225 // selection.collapse_to(
6226 // movement::end_of_paragraph(map, selection.head(), 1),
6227 // SelectionGoal::None,
6228 // )
6229 // });
6230 // })
6231 // }
6232
6233 // pub fn select_to_start_of_paragraph(
6234 // &mut self,
6235 // _: &SelectToStartOfParagraph,
6236 // cx: &mut ViewContext<Self>,
6237 // ) {
6238 // if matches!(self.mode, EditorMode::SingleLine) {
6239 // cx.propagate_action();
6240 // return;
6241 // }
6242
6243 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6244 // s.move_heads_with(|map, head, _| {
6245 // (
6246 // movement::start_of_paragraph(map, head, 1),
6247 // SelectionGoal::None,
6248 // )
6249 // });
6250 // })
6251 // }
6252
6253 // pub fn select_to_end_of_paragraph(
6254 // &mut self,
6255 // _: &SelectToEndOfParagraph,
6256 // cx: &mut ViewContext<Self>,
6257 // ) {
6258 // if matches!(self.mode, EditorMode::SingleLine) {
6259 // cx.propagate_action();
6260 // return;
6261 // }
6262
6263 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6264 // s.move_heads_with(|map, head, _| {
6265 // (
6266 // movement::end_of_paragraph(map, head, 1),
6267 // SelectionGoal::None,
6268 // )
6269 // });
6270 // })
6271 // }
6272
6273 // pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
6274 // if matches!(self.mode, EditorMode::SingleLine) {
6275 // cx.propagate_action();
6276 // return;
6277 // }
6278
6279 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6280 // s.select_ranges(vec![0..0]);
6281 // });
6282 // }
6283
6284 // pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
6285 // let mut selection = self.selections.last::<Point>(cx);
6286 // selection.set_head(Point::zero(), SelectionGoal::None);
6287
6288 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6289 // s.select(vec![selection]);
6290 // });
6291 // }
6292
6293 // pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
6294 // if matches!(self.mode, EditorMode::SingleLine) {
6295 // cx.propagate_action();
6296 // return;
6297 // }
6298
6299 // let cursor = self.buffer.read(cx).read(cx).len();
6300 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6301 // s.select_ranges(vec![cursor..cursor])
6302 // });
6303 // }
6304
6305 // pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
6306 // self.nav_history = nav_history;
6307 // }
6308
6309 // pub fn nav_history(&self) -> Option<&ItemNavHistory> {
6310 // self.nav_history.as_ref()
6311 // }
6312
6313 fn push_to_nav_history(
6314 &mut self,
6315 cursor_anchor: Anchor,
6316 new_position: Option<Point>,
6317 cx: &mut ViewContext<Self>,
6318 ) {
6319 if let Some(nav_history) = self.nav_history.as_mut() {
6320 let buffer = self.buffer.read(cx).read(cx);
6321 let cursor_position = cursor_anchor.to_point(&buffer);
6322 let scroll_state = self.scroll_manager.anchor();
6323 let scroll_top_row = scroll_state.top_row(&buffer);
6324 drop(buffer);
6325
6326 if let Some(new_position) = new_position {
6327 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
6328 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
6329 return;
6330 }
6331 }
6332
6333 nav_history.push(
6334 Some(NavigationData {
6335 cursor_anchor,
6336 cursor_position,
6337 scroll_anchor: scroll_state,
6338 scroll_top_row,
6339 }),
6340 cx,
6341 );
6342 }
6343 }
6344
6345 // pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
6346 // let buffer = self.buffer.read(cx).snapshot(cx);
6347 // let mut selection = self.selections.first::<usize>(cx);
6348 // selection.set_head(buffer.len(), SelectionGoal::None);
6349 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6350 // s.select(vec![selection]);
6351 // });
6352 // }
6353
6354 // pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
6355 // let end = self.buffer.read(cx).read(cx).len();
6356 // self.change_selections(None, cx, |s| {
6357 // s.select_ranges(vec![0..end]);
6358 // });
6359 // }
6360
6361 // pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
6362 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6363 // let mut selections = self.selections.all::<Point>(cx);
6364 // let max_point = display_map.buffer_snapshot.max_point();
6365 // for selection in &mut selections {
6366 // let rows = selection.spanned_rows(true, &display_map);
6367 // selection.start = Point::new(rows.start, 0);
6368 // selection.end = cmp::min(max_point, Point::new(rows.end, 0));
6369 // selection.reversed = false;
6370 // }
6371 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6372 // s.select(selections);
6373 // });
6374 // }
6375
6376 // pub fn split_selection_into_lines(
6377 // &mut self,
6378 // _: &SplitSelectionIntoLines,
6379 // cx: &mut ViewContext<Self>,
6380 // ) {
6381 // let mut to_unfold = Vec::new();
6382 // let mut new_selection_ranges = Vec::new();
6383 // {
6384 // let selections = self.selections.all::<Point>(cx);
6385 // let buffer = self.buffer.read(cx).read(cx);
6386 // for selection in selections {
6387 // for row in selection.start.row..selection.end.row {
6388 // let cursor = Point::new(row, buffer.line_len(row));
6389 // new_selection_ranges.push(cursor..cursor);
6390 // }
6391 // new_selection_ranges.push(selection.end..selection.end);
6392 // to_unfold.push(selection.start..selection.end);
6393 // }
6394 // }
6395 // self.unfold_ranges(to_unfold, true, true, cx);
6396 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6397 // s.select_ranges(new_selection_ranges);
6398 // });
6399 // }
6400
6401 // pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
6402 // self.add_selection(true, cx);
6403 // }
6404
6405 // pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
6406 // self.add_selection(false, cx);
6407 // }
6408
6409 // fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
6410 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6411 // let mut selections = self.selections.all::<Point>(cx);
6412 // let text_layout_details = self.text_layout_details(cx);
6413 // let mut state = self.add_selections_state.take().unwrap_or_else(|| {
6414 // let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
6415 // let range = oldest_selection.display_range(&display_map).sorted();
6416
6417 // let start_x = display_map.x_for_point(range.start, &text_layout_details);
6418 // let end_x = display_map.x_for_point(range.end, &text_layout_details);
6419 // let positions = start_x.min(end_x)..start_x.max(end_x);
6420
6421 // selections.clear();
6422 // let mut stack = Vec::new();
6423 // for row in range.start.row()..=range.end.row() {
6424 // if let Some(selection) = self.selections.build_columnar_selection(
6425 // &display_map,
6426 // row,
6427 // &positions,
6428 // oldest_selection.reversed,
6429 // &text_layout_details,
6430 // ) {
6431 // stack.push(selection.id);
6432 // selections.push(selection);
6433 // }
6434 // }
6435
6436 // if above {
6437 // stack.reverse();
6438 // }
6439
6440 // AddSelectionsState { above, stack }
6441 // });
6442
6443 // let last_added_selection = *state.stack.last().unwrap();
6444 // let mut new_selections = Vec::new();
6445 // if above == state.above {
6446 // let end_row = if above {
6447 // 0
6448 // } else {
6449 // display_map.max_point().row()
6450 // };
6451
6452 // 'outer: for selection in selections {
6453 // if selection.id == last_added_selection {
6454 // let range = selection.display_range(&display_map).sorted();
6455 // debug_assert_eq!(range.start.row(), range.end.row());
6456 // let mut row = range.start.row();
6457 // let positions = if let SelectionGoal::HorizontalRange { start, end } =
6458 // selection.goal
6459 // {
6460 // start..end
6461 // } else {
6462 // let start_x = display_map.x_for_point(range.start, &text_layout_details);
6463 // let end_x = display_map.x_for_point(range.end, &text_layout_details);
6464
6465 // start_x.min(end_x)..start_x.max(end_x)
6466 // };
6467
6468 // while row != end_row {
6469 // if above {
6470 // row -= 1;
6471 // } else {
6472 // row += 1;
6473 // }
6474
6475 // if let Some(new_selection) = self.selections.build_columnar_selection(
6476 // &display_map,
6477 // row,
6478 // &positions,
6479 // selection.reversed,
6480 // &text_layout_details,
6481 // ) {
6482 // state.stack.push(new_selection.id);
6483 // if above {
6484 // new_selections.push(new_selection);
6485 // new_selections.push(selection);
6486 // } else {
6487 // new_selections.push(selection);
6488 // new_selections.push(new_selection);
6489 // }
6490
6491 // continue 'outer;
6492 // }
6493 // }
6494 // }
6495
6496 // new_selections.push(selection);
6497 // }
6498 // } else {
6499 // new_selections = selections;
6500 // new_selections.retain(|s| s.id != last_added_selection);
6501 // state.stack.pop();
6502 // }
6503
6504 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6505 // s.select(new_selections);
6506 // });
6507 // if state.stack.len() > 1 {
6508 // self.add_selections_state = Some(state);
6509 // }
6510 // }
6511
6512 // pub fn select_next_match_internal(
6513 // &mut self,
6514 // display_map: &DisplaySnapshot,
6515 // replace_newest: bool,
6516 // autoscroll: Option<Autoscroll>,
6517 // cx: &mut ViewContext<Self>,
6518 // ) -> Result<()> {
6519 // fn select_next_match_ranges(
6520 // this: &mut Editor,
6521 // range: Range<usize>,
6522 // replace_newest: bool,
6523 // auto_scroll: Option<Autoscroll>,
6524 // cx: &mut ViewContext<Editor>,
6525 // ) {
6526 // this.unfold_ranges([range.clone()], false, true, cx);
6527 // this.change_selections(auto_scroll, cx, |s| {
6528 // if replace_newest {
6529 // s.delete(s.newest_anchor().id);
6530 // }
6531 // s.insert_range(range.clone());
6532 // });
6533 // }
6534
6535 // let buffer = &display_map.buffer_snapshot;
6536 // let mut selections = self.selections.all::<usize>(cx);
6537 // if let Some(mut select_next_state) = self.select_next_state.take() {
6538 // let query = &select_next_state.query;
6539 // if !select_next_state.done {
6540 // let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
6541 // let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
6542 // let mut next_selected_range = None;
6543
6544 // let bytes_after_last_selection =
6545 // buffer.bytes_in_range(last_selection.end..buffer.len());
6546 // let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
6547 // let query_matches = query
6548 // .stream_find_iter(bytes_after_last_selection)
6549 // .map(|result| (last_selection.end, result))
6550 // .chain(
6551 // query
6552 // .stream_find_iter(bytes_before_first_selection)
6553 // .map(|result| (0, result)),
6554 // );
6555
6556 // for (start_offset, query_match) in query_matches {
6557 // let query_match = query_match.unwrap(); // can only fail due to I/O
6558 // let offset_range =
6559 // start_offset + query_match.start()..start_offset + query_match.end();
6560 // let display_range = offset_range.start.to_display_point(&display_map)
6561 // ..offset_range.end.to_display_point(&display_map);
6562
6563 // if !select_next_state.wordwise
6564 // || (!movement::is_inside_word(&display_map, display_range.start)
6565 // && !movement::is_inside_word(&display_map, display_range.end))
6566 // {
6567 // if selections
6568 // .iter()
6569 // .find(|selection| selection.range().overlaps(&offset_range))
6570 // .is_none()
6571 // {
6572 // next_selected_range = Some(offset_range);
6573 // break;
6574 // }
6575 // }
6576 // }
6577
6578 // if let Some(next_selected_range) = next_selected_range {
6579 // select_next_match_ranges(
6580 // self,
6581 // next_selected_range,
6582 // replace_newest,
6583 // autoscroll,
6584 // cx,
6585 // );
6586 // } else {
6587 // select_next_state.done = true;
6588 // }
6589 // }
6590
6591 // self.select_next_state = Some(select_next_state);
6592 // } else if selections.len() == 1 {
6593 // let selection = selections.last_mut().unwrap();
6594 // if selection.start == selection.end {
6595 // let word_range = movement::surrounding_word(
6596 // &display_map,
6597 // selection.start.to_display_point(&display_map),
6598 // );
6599 // selection.start = word_range.start.to_offset(&display_map, Bias::Left);
6600 // selection.end = word_range.end.to_offset(&display_map, Bias::Left);
6601 // selection.goal = SelectionGoal::None;
6602 // selection.reversed = false;
6603
6604 // let query = buffer
6605 // .text_for_range(selection.start..selection.end)
6606 // .collect::<String>();
6607
6608 // let is_empty = query.is_empty();
6609 // let select_state = SelectNextState {
6610 // query: AhoCorasick::new(&[query])?,
6611 // wordwise: true,
6612 // done: is_empty,
6613 // };
6614 // select_next_match_ranges(
6615 // self,
6616 // selection.start..selection.end,
6617 // replace_newest,
6618 // autoscroll,
6619 // cx,
6620 // );
6621 // self.select_next_state = Some(select_state);
6622 // } else {
6623 // let query = buffer
6624 // .text_for_range(selection.start..selection.end)
6625 // .collect::<String>();
6626 // self.select_next_state = Some(SelectNextState {
6627 // query: AhoCorasick::new(&[query])?,
6628 // wordwise: false,
6629 // done: false,
6630 // });
6631 // self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
6632 // }
6633 // }
6634 // Ok(())
6635 // }
6636
6637 // pub fn select_all_matches(
6638 // &mut self,
6639 // action: &SelectAllMatches,
6640 // cx: &mut ViewContext<Self>,
6641 // ) -> Result<()> {
6642 // self.push_to_selection_history();
6643 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6644
6645 // loop {
6646 // self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?;
6647
6648 // if self
6649 // .select_next_state
6650 // .as_ref()
6651 // .map(|selection_state| selection_state.done)
6652 // .unwrap_or(true)
6653 // {
6654 // break;
6655 // }
6656 // }
6657
6658 // Ok(())
6659 // }
6660
6661 // pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
6662 // self.push_to_selection_history();
6663 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6664 // self.select_next_match_internal(
6665 // &display_map,
6666 // action.replace_newest,
6667 // Some(Autoscroll::newest()),
6668 // cx,
6669 // )?;
6670 // Ok(())
6671 // }
6672
6673 // pub fn select_previous(
6674 // &mut self,
6675 // action: &SelectPrevious,
6676 // cx: &mut ViewContext<Self>,
6677 // ) -> Result<()> {
6678 // self.push_to_selection_history();
6679 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6680 // let buffer = &display_map.buffer_snapshot;
6681 // let mut selections = self.selections.all::<usize>(cx);
6682 // if let Some(mut select_prev_state) = self.select_prev_state.take() {
6683 // let query = &select_prev_state.query;
6684 // if !select_prev_state.done {
6685 // let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
6686 // let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
6687 // let mut next_selected_range = None;
6688 // // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
6689 // let bytes_before_last_selection =
6690 // buffer.reversed_bytes_in_range(0..last_selection.start);
6691 // let bytes_after_first_selection =
6692 // buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
6693 // let query_matches = query
6694 // .stream_find_iter(bytes_before_last_selection)
6695 // .map(|result| (last_selection.start, result))
6696 // .chain(
6697 // query
6698 // .stream_find_iter(bytes_after_first_selection)
6699 // .map(|result| (buffer.len(), result)),
6700 // );
6701 // for (end_offset, query_match) in query_matches {
6702 // let query_match = query_match.unwrap(); // can only fail due to I/O
6703 // let offset_range =
6704 // end_offset - query_match.end()..end_offset - query_match.start();
6705 // let display_range = offset_range.start.to_display_point(&display_map)
6706 // ..offset_range.end.to_display_point(&display_map);
6707
6708 // if !select_prev_state.wordwise
6709 // || (!movement::is_inside_word(&display_map, display_range.start)
6710 // && !movement::is_inside_word(&display_map, display_range.end))
6711 // {
6712 // next_selected_range = Some(offset_range);
6713 // break;
6714 // }
6715 // }
6716
6717 // if let Some(next_selected_range) = next_selected_range {
6718 // self.unfold_ranges([next_selected_range.clone()], false, true, cx);
6719 // self.change_selections(Some(Autoscroll::newest()), cx, |s| {
6720 // if action.replace_newest {
6721 // s.delete(s.newest_anchor().id);
6722 // }
6723 // s.insert_range(next_selected_range);
6724 // });
6725 // } else {
6726 // select_prev_state.done = true;
6727 // }
6728 // }
6729
6730 // self.select_prev_state = Some(select_prev_state);
6731 // } else if selections.len() == 1 {
6732 // let selection = selections.last_mut().unwrap();
6733 // if selection.start == selection.end {
6734 // let word_range = movement::surrounding_word(
6735 // &display_map,
6736 // selection.start.to_display_point(&display_map),
6737 // );
6738 // selection.start = word_range.start.to_offset(&display_map, Bias::Left);
6739 // selection.end = word_range.end.to_offset(&display_map, Bias::Left);
6740 // selection.goal = SelectionGoal::None;
6741 // selection.reversed = false;
6742
6743 // let query = buffer
6744 // .text_for_range(selection.start..selection.end)
6745 // .collect::<String>();
6746 // let query = query.chars().rev().collect::<String>();
6747 // let select_state = SelectNextState {
6748 // query: AhoCorasick::new(&[query])?,
6749 // wordwise: true,
6750 // done: false,
6751 // };
6752 // self.unfold_ranges([selection.start..selection.end], false, true, cx);
6753 // self.change_selections(Some(Autoscroll::newest()), cx, |s| {
6754 // s.select(selections);
6755 // });
6756 // self.select_prev_state = Some(select_state);
6757 // } else {
6758 // let query = buffer
6759 // .text_for_range(selection.start..selection.end)
6760 // .collect::<String>();
6761 // let query = query.chars().rev().collect::<String>();
6762 // self.select_prev_state = Some(SelectNextState {
6763 // query: AhoCorasick::new(&[query])?,
6764 // wordwise: false,
6765 // done: false,
6766 // });
6767 // self.select_previous(action, cx)?;
6768 // }
6769 // }
6770 // Ok(())
6771 // }
6772
6773 // pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
6774 // let text_layout_details = &self.text_layout_details(cx);
6775 // self.transact(cx, |this, cx| {
6776 // let mut selections = this.selections.all::<Point>(cx);
6777 // let mut edits = Vec::new();
6778 // let mut selection_edit_ranges = Vec::new();
6779 // let mut last_toggled_row = None;
6780 // let snapshot = this.buffer.read(cx).read(cx);
6781 // let empty_str: Arc<str> = "".into();
6782 // let mut suffixes_inserted = Vec::new();
6783
6784 // fn comment_prefix_range(
6785 // snapshot: &MultiBufferSnapshot,
6786 // row: u32,
6787 // comment_prefix: &str,
6788 // comment_prefix_whitespace: &str,
6789 // ) -> Range<Point> {
6790 // let start = Point::new(row, snapshot.indent_size_for_line(row).len);
6791
6792 // let mut line_bytes = snapshot
6793 // .bytes_in_range(start..snapshot.max_point())
6794 // .flatten()
6795 // .copied();
6796
6797 // // If this line currently begins with the line comment prefix, then record
6798 // // the range containing the prefix.
6799 // if line_bytes
6800 // .by_ref()
6801 // .take(comment_prefix.len())
6802 // .eq(comment_prefix.bytes())
6803 // {
6804 // // Include any whitespace that matches the comment prefix.
6805 // let matching_whitespace_len = line_bytes
6806 // .zip(comment_prefix_whitespace.bytes())
6807 // .take_while(|(a, b)| a == b)
6808 // .count() as u32;
6809 // let end = Point::new(
6810 // start.row,
6811 // start.column + comment_prefix.len() as u32 + matching_whitespace_len,
6812 // );
6813 // start..end
6814 // } else {
6815 // start..start
6816 // }
6817 // }
6818
6819 // fn comment_suffix_range(
6820 // snapshot: &MultiBufferSnapshot,
6821 // row: u32,
6822 // comment_suffix: &str,
6823 // comment_suffix_has_leading_space: bool,
6824 // ) -> Range<Point> {
6825 // let end = Point::new(row, snapshot.line_len(row));
6826 // let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
6827
6828 // let mut line_end_bytes = snapshot
6829 // .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
6830 // .flatten()
6831 // .copied();
6832
6833 // let leading_space_len = if suffix_start_column > 0
6834 // && line_end_bytes.next() == Some(b' ')
6835 // && comment_suffix_has_leading_space
6836 // {
6837 // 1
6838 // } else {
6839 // 0
6840 // };
6841
6842 // // If this line currently begins with the line comment prefix, then record
6843 // // the range containing the prefix.
6844 // if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
6845 // let start = Point::new(end.row, suffix_start_column - leading_space_len);
6846 // start..end
6847 // } else {
6848 // end..end
6849 // }
6850 // }
6851
6852 // // TODO: Handle selections that cross excerpts
6853 // for selection in &mut selections {
6854 // let start_column = snapshot.indent_size_for_line(selection.start.row).len;
6855 // let language = if let Some(language) =
6856 // snapshot.language_scope_at(Point::new(selection.start.row, start_column))
6857 // {
6858 // language
6859 // } else {
6860 // continue;
6861 // };
6862
6863 // selection_edit_ranges.clear();
6864
6865 // // If multiple selections contain a given row, avoid processing that
6866 // // row more than once.
6867 // let mut start_row = selection.start.row;
6868 // if last_toggled_row == Some(start_row) {
6869 // start_row += 1;
6870 // }
6871 // let end_row =
6872 // if selection.end.row > selection.start.row && selection.end.column == 0 {
6873 // selection.end.row - 1
6874 // } else {
6875 // selection.end.row
6876 // };
6877 // last_toggled_row = Some(end_row);
6878
6879 // if start_row > end_row {
6880 // continue;
6881 // }
6882
6883 // // If the language has line comments, toggle those.
6884 // if let Some(full_comment_prefix) = language.line_comment_prefix() {
6885 // // Split the comment prefix's trailing whitespace into a separate string,
6886 // // as that portion won't be used for detecting if a line is a comment.
6887 // let comment_prefix = full_comment_prefix.trim_end_matches(' ');
6888 // let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
6889 // let mut all_selection_lines_are_comments = true;
6890
6891 // for row in start_row..=end_row {
6892 // if snapshot.is_line_blank(row) && start_row < end_row {
6893 // continue;
6894 // }
6895
6896 // let prefix_range = comment_prefix_range(
6897 // snapshot.deref(),
6898 // row,
6899 // comment_prefix,
6900 // comment_prefix_whitespace,
6901 // );
6902 // if prefix_range.is_empty() {
6903 // all_selection_lines_are_comments = false;
6904 // }
6905 // selection_edit_ranges.push(prefix_range);
6906 // }
6907
6908 // if all_selection_lines_are_comments {
6909 // edits.extend(
6910 // selection_edit_ranges
6911 // .iter()
6912 // .cloned()
6913 // .map(|range| (range, empty_str.clone())),
6914 // );
6915 // } else {
6916 // let min_column = selection_edit_ranges
6917 // .iter()
6918 // .map(|r| r.start.column)
6919 // .min()
6920 // .unwrap_or(0);
6921 // edits.extend(selection_edit_ranges.iter().map(|range| {
6922 // let position = Point::new(range.start.row, min_column);
6923 // (position..position, full_comment_prefix.clone())
6924 // }));
6925 // }
6926 // } else if let Some((full_comment_prefix, comment_suffix)) =
6927 // language.block_comment_delimiters()
6928 // {
6929 // let comment_prefix = full_comment_prefix.trim_end_matches(' ');
6930 // let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
6931 // let prefix_range = comment_prefix_range(
6932 // snapshot.deref(),
6933 // start_row,
6934 // comment_prefix,
6935 // comment_prefix_whitespace,
6936 // );
6937 // let suffix_range = comment_suffix_range(
6938 // snapshot.deref(),
6939 // end_row,
6940 // comment_suffix.trim_start_matches(' '),
6941 // comment_suffix.starts_with(' '),
6942 // );
6943
6944 // if prefix_range.is_empty() || suffix_range.is_empty() {
6945 // edits.push((
6946 // prefix_range.start..prefix_range.start,
6947 // full_comment_prefix.clone(),
6948 // ));
6949 // edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
6950 // suffixes_inserted.push((end_row, comment_suffix.len()));
6951 // } else {
6952 // edits.push((prefix_range, empty_str.clone()));
6953 // edits.push((suffix_range, empty_str.clone()));
6954 // }
6955 // } else {
6956 // continue;
6957 // }
6958 // }
6959
6960 // drop(snapshot);
6961 // this.buffer.update(cx, |buffer, cx| {
6962 // buffer.edit(edits, None, cx);
6963 // });
6964
6965 // // Adjust selections so that they end before any comment suffixes that
6966 // // were inserted.
6967 // let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
6968 // let mut selections = this.selections.all::<Point>(cx);
6969 // let snapshot = this.buffer.read(cx).read(cx);
6970 // for selection in &mut selections {
6971 // while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
6972 // match row.cmp(&selection.end.row) {
6973 // Ordering::Less => {
6974 // suffixes_inserted.next();
6975 // continue;
6976 // }
6977 // Ordering::Greater => break,
6978 // Ordering::Equal => {
6979 // if selection.end.column == snapshot.line_len(row) {
6980 // if selection.is_empty() {
6981 // selection.start.column -= suffix_len as u32;
6982 // }
6983 // selection.end.column -= suffix_len as u32;
6984 // }
6985 // break;
6986 // }
6987 // }
6988 // }
6989 // }
6990
6991 // drop(snapshot);
6992 // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
6993
6994 // let selections = this.selections.all::<Point>(cx);
6995 // let selections_on_single_row = selections.windows(2).all(|selections| {
6996 // selections[0].start.row == selections[1].start.row
6997 // && selections[0].end.row == selections[1].end.row
6998 // && selections[0].start.row == selections[0].end.row
6999 // });
7000 // let selections_selecting = selections
7001 // .iter()
7002 // .any(|selection| selection.start != selection.end);
7003 // let advance_downwards = action.advance_downwards
7004 // && selections_on_single_row
7005 // && !selections_selecting
7006 // && this.mode != EditorMode::SingleLine;
7007
7008 // if advance_downwards {
7009 // let snapshot = this.buffer.read(cx).snapshot(cx);
7010
7011 // this.change_selections(Some(Autoscroll::fit()), cx, |s| {
7012 // s.move_cursors_with(|display_snapshot, display_point, _| {
7013 // let mut point = display_point.to_point(display_snapshot);
7014 // point.row += 1;
7015 // point = snapshot.clip_point(point, Bias::Left);
7016 // let display_point = point.to_display_point(display_snapshot);
7017 // let goal = SelectionGoal::HorizontalPosition(
7018 // display_snapshot.x_for_point(display_point, &text_layout_details),
7019 // );
7020 // (display_point, goal)
7021 // })
7022 // });
7023 // }
7024 // });
7025 // }
7026
7027 // pub fn select_larger_syntax_node(
7028 // &mut self,
7029 // _: &SelectLargerSyntaxNode,
7030 // cx: &mut ViewContext<Self>,
7031 // ) {
7032 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7033 // let buffer = self.buffer.read(cx).snapshot(cx);
7034 // let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
7035
7036 // let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
7037 // let mut selected_larger_node = false;
7038 // let new_selections = old_selections
7039 // .iter()
7040 // .map(|selection| {
7041 // let old_range = selection.start..selection.end;
7042 // let mut new_range = old_range.clone();
7043 // while let Some(containing_range) =
7044 // buffer.range_for_syntax_ancestor(new_range.clone())
7045 // {
7046 // new_range = containing_range;
7047 // if !display_map.intersects_fold(new_range.start)
7048 // && !display_map.intersects_fold(new_range.end)
7049 // {
7050 // break;
7051 // }
7052 // }
7053
7054 // selected_larger_node |= new_range != old_range;
7055 // Selection {
7056 // id: selection.id,
7057 // start: new_range.start,
7058 // end: new_range.end,
7059 // goal: SelectionGoal::None,
7060 // reversed: selection.reversed,
7061 // }
7062 // })
7063 // .collect::<Vec<_>>();
7064
7065 // if selected_larger_node {
7066 // stack.push(old_selections);
7067 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7068 // s.select(new_selections);
7069 // });
7070 // }
7071 // self.select_larger_syntax_node_stack = stack;
7072 // }
7073
7074 // pub fn select_smaller_syntax_node(
7075 // &mut self,
7076 // _: &SelectSmallerSyntaxNode,
7077 // cx: &mut ViewContext<Self>,
7078 // ) {
7079 // let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
7080 // if let Some(selections) = stack.pop() {
7081 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7082 // s.select(selections.to_vec());
7083 // });
7084 // }
7085 // self.select_larger_syntax_node_stack = stack;
7086 // }
7087
7088 // pub fn move_to_enclosing_bracket(
7089 // &mut self,
7090 // _: &MoveToEnclosingBracket,
7091 // cx: &mut ViewContext<Self>,
7092 // ) {
7093 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7094 // s.move_offsets_with(|snapshot, selection| {
7095 // let Some(enclosing_bracket_ranges) =
7096 // snapshot.enclosing_bracket_ranges(selection.start..selection.end)
7097 // else {
7098 // return;
7099 // };
7100
7101 // let mut best_length = usize::MAX;
7102 // let mut best_inside = false;
7103 // let mut best_in_bracket_range = false;
7104 // let mut best_destination = None;
7105 // for (open, close) in enclosing_bracket_ranges {
7106 // let close = close.to_inclusive();
7107 // let length = close.end() - open.start;
7108 // let inside = selection.start >= open.end && selection.end <= *close.start();
7109 // let in_bracket_range = open.to_inclusive().contains(&selection.head())
7110 // || close.contains(&selection.head());
7111
7112 // // If best is next to a bracket and current isn't, skip
7113 // if !in_bracket_range && best_in_bracket_range {
7114 // continue;
7115 // }
7116
7117 // // Prefer smaller lengths unless best is inside and current isn't
7118 // if length > best_length && (best_inside || !inside) {
7119 // continue;
7120 // }
7121
7122 // best_length = length;
7123 // best_inside = inside;
7124 // best_in_bracket_range = in_bracket_range;
7125 // best_destination = Some(
7126 // if close.contains(&selection.start) && close.contains(&selection.end) {
7127 // if inside {
7128 // open.end
7129 // } else {
7130 // open.start
7131 // }
7132 // } else {
7133 // if inside {
7134 // *close.start()
7135 // } else {
7136 // *close.end()
7137 // }
7138 // },
7139 // );
7140 // }
7141
7142 // if let Some(destination) = best_destination {
7143 // selection.collapse_to(destination, SelectionGoal::None);
7144 // }
7145 // })
7146 // });
7147 // }
7148
7149 // pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
7150 // self.end_selection(cx);
7151 // self.selection_history.mode = SelectionHistoryMode::Undoing;
7152 // if let Some(entry) = self.selection_history.undo_stack.pop_back() {
7153 // self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
7154 // self.select_next_state = entry.select_next_state;
7155 // self.select_prev_state = entry.select_prev_state;
7156 // self.add_selections_state = entry.add_selections_state;
7157 // self.request_autoscroll(Autoscroll::newest(), cx);
7158 // }
7159 // self.selection_history.mode = SelectionHistoryMode::Normal;
7160 // }
7161
7162 // pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
7163 // self.end_selection(cx);
7164 // self.selection_history.mode = SelectionHistoryMode::Redoing;
7165 // if let Some(entry) = self.selection_history.redo_stack.pop_back() {
7166 // self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
7167 // self.select_next_state = entry.select_next_state;
7168 // self.select_prev_state = entry.select_prev_state;
7169 // self.add_selections_state = entry.add_selections_state;
7170 // self.request_autoscroll(Autoscroll::newest(), cx);
7171 // }
7172 // self.selection_history.mode = SelectionHistoryMode::Normal;
7173 // }
7174
7175 // fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
7176 // self.go_to_diagnostic_impl(Direction::Next, cx)
7177 // }
7178
7179 // fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
7180 // self.go_to_diagnostic_impl(Direction::Prev, cx)
7181 // }
7182
7183 // pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
7184 // let buffer = self.buffer.read(cx).snapshot(cx);
7185 // let selection = self.selections.newest::<usize>(cx);
7186
7187 // // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
7188 // if direction == Direction::Next {
7189 // if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
7190 // let (group_id, jump_to) = popover.activation_info();
7191 // if self.activate_diagnostics(group_id, cx) {
7192 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7193 // let mut new_selection = s.newest_anchor().clone();
7194 // new_selection.collapse_to(jump_to, SelectionGoal::None);
7195 // s.select_anchors(vec![new_selection.clone()]);
7196 // });
7197 // }
7198 // return;
7199 // }
7200 // }
7201
7202 // let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
7203 // active_diagnostics
7204 // .primary_range
7205 // .to_offset(&buffer)
7206 // .to_inclusive()
7207 // });
7208 // let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
7209 // if active_primary_range.contains(&selection.head()) {
7210 // *active_primary_range.end()
7211 // } else {
7212 // selection.head()
7213 // }
7214 // } else {
7215 // selection.head()
7216 // };
7217
7218 // loop {
7219 // let mut diagnostics = if direction == Direction::Prev {
7220 // buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
7221 // } else {
7222 // buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
7223 // };
7224 // let group = diagnostics.find_map(|entry| {
7225 // if entry.diagnostic.is_primary
7226 // && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
7227 // && !entry.range.is_empty()
7228 // && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
7229 // && !entry.range.contains(&search_start)
7230 // {
7231 // Some((entry.range, entry.diagnostic.group_id))
7232 // } else {
7233 // None
7234 // }
7235 // });
7236
7237 // if let Some((primary_range, group_id)) = group {
7238 // if self.activate_diagnostics(group_id, cx) {
7239 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7240 // s.select(vec![Selection {
7241 // id: selection.id,
7242 // start: primary_range.start,
7243 // end: primary_range.start,
7244 // reversed: false,
7245 // goal: SelectionGoal::None,
7246 // }]);
7247 // });
7248 // }
7249 // break;
7250 // } else {
7251 // // Cycle around to the start of the buffer, potentially moving back to the start of
7252 // // the currently active diagnostic.
7253 // active_primary_range.take();
7254 // if direction == Direction::Prev {
7255 // if search_start == buffer.len() {
7256 // break;
7257 // } else {
7258 // search_start = buffer.len();
7259 // }
7260 // } else if search_start == 0 {
7261 // break;
7262 // } else {
7263 // search_start = 0;
7264 // }
7265 // }
7266 // }
7267 // }
7268
7269 // fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
7270 // let snapshot = self
7271 // .display_map
7272 // .update(cx, |display_map, cx| display_map.snapshot(cx));
7273 // let selection = self.selections.newest::<Point>(cx);
7274
7275 // if !self.seek_in_direction(
7276 // &snapshot,
7277 // selection.head(),
7278 // false,
7279 // snapshot
7280 // .buffer_snapshot
7281 // .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
7282 // cx,
7283 // ) {
7284 // let wrapped_point = Point::zero();
7285 // self.seek_in_direction(
7286 // &snapshot,
7287 // wrapped_point,
7288 // true,
7289 // snapshot
7290 // .buffer_snapshot
7291 // .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
7292 // cx,
7293 // );
7294 // }
7295 // }
7296
7297 // fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
7298 // let snapshot = self
7299 // .display_map
7300 // .update(cx, |display_map, cx| display_map.snapshot(cx));
7301 // let selection = self.selections.newest::<Point>(cx);
7302
7303 // if !self.seek_in_direction(
7304 // &snapshot,
7305 // selection.head(),
7306 // false,
7307 // snapshot
7308 // .buffer_snapshot
7309 // .git_diff_hunks_in_range_rev(0..selection.head().row),
7310 // cx,
7311 // ) {
7312 // let wrapped_point = snapshot.buffer_snapshot.max_point();
7313 // self.seek_in_direction(
7314 // &snapshot,
7315 // wrapped_point,
7316 // true,
7317 // snapshot
7318 // .buffer_snapshot
7319 // .git_diff_hunks_in_range_rev(0..wrapped_point.row),
7320 // cx,
7321 // );
7322 // }
7323 // }
7324
7325 // fn seek_in_direction(
7326 // &mut self,
7327 // snapshot: &DisplaySnapshot,
7328 // initial_point: Point,
7329 // is_wrapped: bool,
7330 // hunks: impl Iterator<Item = DiffHunk<u32>>,
7331 // cx: &mut ViewContext<Editor>,
7332 // ) -> bool {
7333 // let display_point = initial_point.to_display_point(snapshot);
7334 // let mut hunks = hunks
7335 // .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
7336 // .filter(|hunk| {
7337 // if is_wrapped {
7338 // true
7339 // } else {
7340 // !hunk.contains_display_row(display_point.row())
7341 // }
7342 // })
7343 // .dedup();
7344
7345 // if let Some(hunk) = hunks.next() {
7346 // self.change_selections(Some(Autoscroll::fit()), cx, |s| {
7347 // let row = hunk.start_display_row();
7348 // let point = DisplayPoint::new(row, 0);
7349 // s.select_display_ranges([point..point]);
7350 // });
7351
7352 // true
7353 // } else {
7354 // false
7355 // }
7356 // }
7357
7358 pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
7359 self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
7360 }
7361
7362 pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
7363 self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
7364 }
7365
7366 pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
7367 self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
7368 }
7369
7370 pub fn go_to_type_definition_split(
7371 &mut self,
7372 _: &GoToTypeDefinitionSplit,
7373 cx: &mut ViewContext<Self>,
7374 ) {
7375 self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
7376 }
7377
7378 fn go_to_definition_of_kind(
7379 &mut self,
7380 kind: GotoDefinitionKind,
7381 split: bool,
7382 cx: &mut ViewContext<Self>,
7383 ) {
7384 let Some(workspace) = self.workspace() else {
7385 return;
7386 };
7387 let buffer = self.buffer.read(cx);
7388 let head = self.selections.newest::<usize>(cx).head();
7389 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
7390 text_anchor
7391 } else {
7392 return;
7393 };
7394
7395 let project = workspace.read(cx).project().clone();
7396 let definitions = project.update(cx, |project, cx| match kind {
7397 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
7398 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
7399 });
7400
7401 cx.spawn(|editor, mut cx| async move {
7402 let definitions = definitions.await?;
7403 editor.update(&mut cx, |editor, cx| {
7404 editor.navigate_to_definitions(
7405 definitions
7406 .into_iter()
7407 .map(GoToDefinitionLink::Text)
7408 .collect(),
7409 split,
7410 cx,
7411 );
7412 })?;
7413 Ok::<(), anyhow::Error>(())
7414 })
7415 .detach_and_log_err(cx);
7416 }
7417
7418 pub fn navigate_to_definitions(
7419 &mut self,
7420 mut definitions: Vec<GoToDefinitionLink>,
7421 split: bool,
7422 cx: &mut ViewContext<Editor>,
7423 ) {
7424 let Some(workspace) = self.workspace() else {
7425 return;
7426 };
7427 let pane = workspace.read(cx).active_pane().clone();
7428 // If there is one definition, just open it directly
7429 if definitions.len() == 1 {
7430 let definition = definitions.pop().unwrap();
7431 let target_task = match definition {
7432 GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
7433 GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
7434 self.compute_target_location(lsp_location, server_id, cx)
7435 }
7436 };
7437 cx.spawn(|editor, mut cx| async move {
7438 let target = target_task.await.context("target resolution task")?;
7439 if let Some(target) = target {
7440 editor.update(&mut cx, |editor, cx| {
7441 let range = target.range.to_offset(target.buffer.read(cx));
7442 let range = editor.range_for_match(&range);
7443 if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
7444 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
7445 s.select_ranges([range]);
7446 });
7447 } else {
7448 cx.window_context().defer(move |cx| {
7449 let target_editor: View<Self> =
7450 workspace.update(cx, |workspace, cx| {
7451 if split {
7452 workspace.split_project_item(target.buffer.clone(), cx)
7453 } else {
7454 workspace.open_project_item(target.buffer.clone(), cx)
7455 }
7456 });
7457 target_editor.update(cx, |target_editor, cx| {
7458 // When selecting a definition in a different buffer, disable the nav history
7459 // to avoid creating a history entry at the previous cursor location.
7460 pane.update(cx, |pane, _| pane.disable_history());
7461 target_editor.change_selections(
7462 Some(Autoscroll::fit()),
7463 cx,
7464 |s| {
7465 s.select_ranges([range]);
7466 },
7467 );
7468 pane.update(cx, |pane, _| pane.enable_history());
7469 });
7470 });
7471 }
7472 })
7473 } else {
7474 Ok(())
7475 }
7476 })
7477 .detach_and_log_err(cx);
7478 } else if !definitions.is_empty() {
7479 let replica_id = self.replica_id(cx);
7480 cx.spawn(|editor, mut cx| async move {
7481 let (title, location_tasks) = editor
7482 .update(&mut cx, |editor, cx| {
7483 let title = definitions
7484 .iter()
7485 .find_map(|definition| match definition {
7486 GoToDefinitionLink::Text(link) => {
7487 link.origin.as_ref().map(|origin| {
7488 let buffer = origin.buffer.read(cx);
7489 format!(
7490 "Definitions for {}",
7491 buffer
7492 .text_for_range(origin.range.clone())
7493 .collect::<String>()
7494 )
7495 })
7496 }
7497 GoToDefinitionLink::InlayHint(_, _) => None,
7498 })
7499 .unwrap_or("Definitions".to_string());
7500 let location_tasks = definitions
7501 .into_iter()
7502 .map(|definition| match definition {
7503 GoToDefinitionLink::Text(link) => {
7504 Task::Ready(Some(Ok(Some(link.target))))
7505 }
7506 GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
7507 editor.compute_target_location(lsp_location, server_id, cx)
7508 }
7509 })
7510 .collect::<Vec<_>>();
7511 (title, location_tasks)
7512 })
7513 .context("location tasks preparation")?;
7514
7515 let locations = futures::future::join_all(location_tasks)
7516 .await
7517 .into_iter()
7518 .filter_map(|location| location.transpose())
7519 .collect::<Result<_>>()
7520 .context("location tasks")?;
7521 workspace.update(&mut cx, |workspace, cx| {
7522 Self::open_locations_in_multibuffer(
7523 workspace, locations, replica_id, title, split, cx,
7524 )
7525 });
7526
7527 anyhow::Ok(())
7528 })
7529 .detach_and_log_err(cx);
7530 }
7531 }
7532
7533 fn compute_target_location(
7534 &self,
7535 lsp_location: lsp::Location,
7536 server_id: LanguageServerId,
7537 cx: &mut ViewContext<Editor>,
7538 ) -> Task<anyhow::Result<Option<Location>>> {
7539 let Some(project) = self.project.clone() else {
7540 return Task::Ready(Some(Ok(None)));
7541 };
7542
7543 cx.spawn(move |editor, mut cx| async move {
7544 let location_task = editor.update(&mut cx, |editor, cx| {
7545 project.update(cx, |project, cx| {
7546 let language_server_name =
7547 editor.buffer.read(cx).as_singleton().and_then(|buffer| {
7548 project
7549 .language_server_for_buffer(buffer.read(cx), server_id, cx)
7550 .map(|(_, lsp_adapter)| {
7551 LanguageServerName(Arc::from(lsp_adapter.name()))
7552 })
7553 });
7554 language_server_name.map(|language_server_name| {
7555 project.open_local_buffer_via_lsp(
7556 lsp_location.uri.clone(),
7557 server_id,
7558 language_server_name,
7559 cx,
7560 )
7561 })
7562 })
7563 })?;
7564 let location = match location_task {
7565 Some(task) => Some({
7566 let target_buffer_handle = task.await.context("open local buffer")?;
7567 let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
7568 let target_start = target_buffer
7569 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
7570 let target_end = target_buffer
7571 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
7572 target_buffer.anchor_after(target_start)
7573 ..target_buffer.anchor_before(target_end)
7574 })?;
7575 Location {
7576 buffer: target_buffer_handle,
7577 range,
7578 }
7579 }),
7580 None => None,
7581 };
7582 Ok(location)
7583 })
7584 }
7585
7586 // pub fn find_all_references(
7587 // workspace: &mut Workspace,
7588 // _: &FindAllReferences,
7589 // cx: &mut ViewContext<Workspace>,
7590 // ) -> Option<Task<Result<()>>> {
7591 // let active_item = workspace.active_item(cx)?;
7592 // let editor_handle = active_item.act_as::<Self>(cx)?;
7593
7594 // let editor = editor_handle.read(cx);
7595 // let buffer = editor.buffer.read(cx);
7596 // let head = editor.selections.newest::<usize>(cx).head();
7597 // let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
7598 // let replica_id = editor.replica_id(cx);
7599
7600 // let project = workspace.project().clone();
7601 // let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
7602 // Some(cx.spawn_labeled(
7603 // "Finding All References...",
7604 // |workspace, mut cx| async move {
7605 // let locations = references.await?;
7606 // if locations.is_empty() {
7607 // return Ok(());
7608 // }
7609
7610 // workspace.update(&mut cx, |workspace, cx| {
7611 // let title = locations
7612 // .first()
7613 // .as_ref()
7614 // .map(|location| {
7615 // let buffer = location.buffer.read(cx);
7616 // format!(
7617 // "References to `{}`",
7618 // buffer
7619 // .text_for_range(location.range.clone())
7620 // .collect::<String>()
7621 // )
7622 // })
7623 // .unwrap();
7624 // Self::open_locations_in_multibuffer(
7625 // workspace, locations, replica_id, title, false, cx,
7626 // );
7627 // })?;
7628
7629 // Ok(())
7630 // },
7631 // ))
7632 // }
7633
7634 /// Opens a multibuffer with the given project locations in it
7635 pub fn open_locations_in_multibuffer(
7636 workspace: &mut Workspace,
7637 mut locations: Vec<Location>,
7638 replica_id: ReplicaId,
7639 title: String,
7640 split: bool,
7641 cx: &mut ViewContext<Workspace>,
7642 ) {
7643 // If there are multiple definitions, open them in a multibuffer
7644 locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
7645 let mut locations = locations.into_iter().peekable();
7646 let mut ranges_to_highlight = Vec::new();
7647
7648 let excerpt_buffer = cx.build_model(|cx| {
7649 let mut multibuffer = MultiBuffer::new(replica_id);
7650 while let Some(location) = locations.next() {
7651 let buffer = location.buffer.read(cx);
7652 let mut ranges_for_buffer = Vec::new();
7653 let range = location.range.to_offset(buffer);
7654 ranges_for_buffer.push(range.clone());
7655
7656 while let Some(next_location) = locations.peek() {
7657 if next_location.buffer == location.buffer {
7658 ranges_for_buffer.push(next_location.range.to_offset(buffer));
7659 locations.next();
7660 } else {
7661 break;
7662 }
7663 }
7664
7665 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
7666 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
7667 location.buffer.clone(),
7668 ranges_for_buffer,
7669 1,
7670 cx,
7671 ))
7672 }
7673
7674 multibuffer.with_title(title)
7675 });
7676
7677 let editor = cx.build_view(|cx| {
7678 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
7679 });
7680 editor.update(cx, |editor, cx| {
7681 editor.highlight_background::<Self>(
7682 ranges_to_highlight,
7683 |theme| todo!("theme.editor.highlighted_line_background"),
7684 cx,
7685 );
7686 });
7687 if split {
7688 workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
7689 } else {
7690 workspace.add_item(Box::new(editor), cx);
7691 }
7692 }
7693
7694 // pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
7695 // use language::ToOffset as _;
7696
7697 // let project = self.project.clone()?;
7698 // let selection = self.selections.newest_anchor().clone();
7699 // let (cursor_buffer, cursor_buffer_position) = self
7700 // .buffer
7701 // .read(cx)
7702 // .text_anchor_for_position(selection.head(), cx)?;
7703 // let (tail_buffer, _) = self
7704 // .buffer
7705 // .read(cx)
7706 // .text_anchor_for_position(selection.tail(), cx)?;
7707 // if tail_buffer != cursor_buffer {
7708 // return None;
7709 // }
7710
7711 // let snapshot = cursor_buffer.read(cx).snapshot();
7712 // let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
7713 // let prepare_rename = project.update(cx, |project, cx| {
7714 // project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
7715 // });
7716
7717 // Some(cx.spawn(|this, mut cx| async move {
7718 // let rename_range = if let Some(range) = prepare_rename.await? {
7719 // Some(range)
7720 // } else {
7721 // this.update(&mut cx, |this, cx| {
7722 // let buffer = this.buffer.read(cx).snapshot(cx);
7723 // let mut buffer_highlights = this
7724 // .document_highlights_for_position(selection.head(), &buffer)
7725 // .filter(|highlight| {
7726 // highlight.start.excerpt_id == selection.head().excerpt_id
7727 // && highlight.end.excerpt_id == selection.head().excerpt_id
7728 // });
7729 // buffer_highlights
7730 // .next()
7731 // .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
7732 // })?
7733 // };
7734 // if let Some(rename_range) = rename_range {
7735 // let rename_buffer_range = rename_range.to_offset(&snapshot);
7736 // let cursor_offset_in_rename_range =
7737 // cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
7738
7739 // this.update(&mut cx, |this, cx| {
7740 // this.take_rename(false, cx);
7741 // let style = this.style(cx);
7742 // let buffer = this.buffer.read(cx).read(cx);
7743 // let cursor_offset = selection.head().to_offset(&buffer);
7744 // let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
7745 // let rename_end = rename_start + rename_buffer_range.len();
7746 // let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
7747 // let mut old_highlight_id = None;
7748 // let old_name: Arc<str> = buffer
7749 // .chunks(rename_start..rename_end, true)
7750 // .map(|chunk| {
7751 // if old_highlight_id.is_none() {
7752 // old_highlight_id = chunk.syntax_highlight_id;
7753 // }
7754 // chunk.text
7755 // })
7756 // .collect::<String>()
7757 // .into();
7758
7759 // drop(buffer);
7760
7761 // // Position the selection in the rename editor so that it matches the current selection.
7762 // this.show_local_selections = false;
7763 // let rename_editor = cx.add_view(|cx| {
7764 // let mut editor = Editor::single_line(None, cx);
7765 // if let Some(old_highlight_id) = old_highlight_id {
7766 // editor.override_text_style =
7767 // Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
7768 // }
7769 // editor.buffer.update(cx, |buffer, cx| {
7770 // buffer.edit([(0..0, old_name.clone())], None, cx)
7771 // });
7772 // editor.select_all(&SelectAll, cx);
7773 // editor
7774 // });
7775
7776 // let ranges = this
7777 // .clear_background_highlights::<DocumentHighlightWrite>(cx)
7778 // .into_iter()
7779 // .flat_map(|(_, ranges)| ranges.into_iter())
7780 // .chain(
7781 // this.clear_background_highlights::<DocumentHighlightRead>(cx)
7782 // .into_iter()
7783 // .flat_map(|(_, ranges)| ranges.into_iter()),
7784 // )
7785 // .collect();
7786
7787 // this.highlight_text::<Rename>(
7788 // ranges,
7789 // HighlightStyle {
7790 // fade_out: Some(style.rename_fade),
7791 // ..Default::default()
7792 // },
7793 // cx,
7794 // );
7795 // cx.focus(&rename_editor);
7796 // let block_id = this.insert_blocks(
7797 // [BlockProperties {
7798 // style: BlockStyle::Flex,
7799 // position: range.start.clone(),
7800 // height: 1,
7801 // render: Arc::new({
7802 // let editor = rename_editor.clone();
7803 // move |cx: &mut BlockContext| {
7804 // ChildView::new(&editor, cx)
7805 // .contained()
7806 // .with_padding_left(cx.anchor_x)
7807 // .into_any()
7808 // }
7809 // }),
7810 // disposition: BlockDisposition::Below,
7811 // }],
7812 // Some(Autoscroll::fit()),
7813 // cx,
7814 // )[0];
7815 // this.pending_rename = Some(RenameState {
7816 // range,
7817 // old_name,
7818 // editor: rename_editor,
7819 // block_id,
7820 // });
7821 // })?;
7822 // }
7823
7824 // Ok(())
7825 // }))
7826 // }
7827
7828 // pub fn confirm_rename(
7829 // workspace: &mut Workspace,
7830 // _: &ConfirmRename,
7831 // cx: &mut ViewContext<Workspace>,
7832 // ) -> Option<Task<Result<()>>> {
7833 // let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
7834
7835 // let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
7836 // let rename = editor.take_rename(false, cx)?;
7837 // let buffer = editor.buffer.read(cx);
7838 // let (start_buffer, start) =
7839 // buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
7840 // let (end_buffer, end) =
7841 // buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
7842 // if start_buffer == end_buffer {
7843 // let new_name = rename.editor.read(cx).text(cx);
7844 // Some((start_buffer, start..end, rename.old_name, new_name))
7845 // } else {
7846 // None
7847 // }
7848 // })?;
7849
7850 // let rename = workspace.project().clone().update(cx, |project, cx| {
7851 // project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
7852 // });
7853
7854 // let editor = editor.downgrade();
7855 // Some(cx.spawn(|workspace, mut cx| async move {
7856 // let project_transaction = rename.await?;
7857 // Self::open_project_transaction(
7858 // &editor,
7859 // workspace,
7860 // project_transaction,
7861 // format!("Rename: {} → {}", old_name, new_name),
7862 // cx.clone(),
7863 // )
7864 // .await?;
7865
7866 // editor.update(&mut cx, |editor, cx| {
7867 // editor.refresh_document_highlights(cx);
7868 // })?;
7869 // Ok(())
7870 // }))
7871 // }
7872
7873 fn take_rename(
7874 &mut self,
7875 moving_cursor: bool,
7876 cx: &mut ViewContext<Self>,
7877 ) -> Option<RenameState> {
7878 let rename = self.pending_rename.take()?;
7879 self.remove_blocks(
7880 [rename.block_id].into_iter().collect(),
7881 Some(Autoscroll::fit()),
7882 cx,
7883 );
7884 self.clear_highlights::<Rename>(cx);
7885 self.show_local_selections = true;
7886
7887 if moving_cursor {
7888 let rename_editor = rename.editor.read(cx);
7889 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
7890
7891 // Update the selection to match the position of the selection inside
7892 // the rename editor.
7893 let snapshot = self.buffer.read(cx).read(cx);
7894 let rename_range = rename.range.to_offset(&snapshot);
7895 let cursor_in_editor = snapshot
7896 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
7897 .min(rename_range.end);
7898 drop(snapshot);
7899
7900 self.change_selections(None, cx, |s| {
7901 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
7902 });
7903 } else {
7904 self.refresh_document_highlights(cx);
7905 }
7906
7907 Some(rename)
7908 }
7909
7910 #[cfg(any(test, feature = "test-support"))]
7911 pub fn pending_rename(&self) -> Option<&RenameState> {
7912 self.pending_rename.as_ref()
7913 }
7914
7915 // fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
7916 // let project = match &self.project {
7917 // Some(project) => project.clone(),
7918 // None => return None,
7919 // };
7920
7921 // Some(self.perform_format(project, FormatTrigger::Manual, cx))
7922 // }
7923
7924 fn perform_format(
7925 &mut self,
7926 project: Model<Project>,
7927 trigger: FormatTrigger,
7928 cx: &mut ViewContext<Self>,
7929 ) -> Task<Result<()>> {
7930 let buffer = self.buffer().clone();
7931 let buffers = buffer.read(cx).all_buffers();
7932
7933 let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
7934 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
7935
7936 cx.spawn(|_, mut cx| async move {
7937 let transaction = futures::select_biased! {
7938 _ = timeout => {
7939 log::warn!("timed out waiting for formatting");
7940 None
7941 }
7942 transaction = format.log_err().fuse() => transaction,
7943 };
7944
7945 buffer.update(&mut cx, |buffer, cx| {
7946 if let Some(transaction) = transaction {
7947 if !buffer.is_singleton() {
7948 buffer.push_transaction(&transaction.0, cx);
7949 }
7950 }
7951
7952 cx.notify();
7953 });
7954
7955 Ok(())
7956 })
7957 }
7958
7959 // fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
7960 // if let Some(project) = self.project.clone() {
7961 // self.buffer.update(cx, |multi_buffer, cx| {
7962 // project.update(cx, |project, cx| {
7963 // project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
7964 // });
7965 // })
7966 // }
7967 // }
7968
7969 // fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
7970 // cx.show_character_palette();
7971 // }
7972
7973 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
7974 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
7975 let buffer = self.buffer.read(cx).snapshot(cx);
7976 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
7977 let is_valid = buffer
7978 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
7979 .any(|entry| {
7980 entry.diagnostic.is_primary
7981 && !entry.range.is_empty()
7982 && entry.range.start == primary_range_start
7983 && entry.diagnostic.message == active_diagnostics.primary_message
7984 });
7985
7986 if is_valid != active_diagnostics.is_valid {
7987 active_diagnostics.is_valid = is_valid;
7988 let mut new_styles = HashMap::default();
7989 for (block_id, diagnostic) in &active_diagnostics.blocks {
7990 new_styles.insert(
7991 *block_id,
7992 diagnostic_block_renderer(diagnostic.clone(), is_valid),
7993 );
7994 }
7995 self.display_map
7996 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
7997 }
7998 }
7999 }
8000
8001 // fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
8002 // self.dismiss_diagnostics(cx);
8003 // self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
8004 // let buffer = self.buffer.read(cx).snapshot(cx);
8005
8006 // let mut primary_range = None;
8007 // let mut primary_message = None;
8008 // let mut group_end = Point::zero();
8009 // let diagnostic_group = buffer
8010 // .diagnostic_group::<Point>(group_id)
8011 // .map(|entry| {
8012 // if entry.range.end > group_end {
8013 // group_end = entry.range.end;
8014 // }
8015 // if entry.diagnostic.is_primary {
8016 // primary_range = Some(entry.range.clone());
8017 // primary_message = Some(entry.diagnostic.message.clone());
8018 // }
8019 // entry
8020 // })
8021 // .collect::<Vec<_>>();
8022 // let primary_range = primary_range?;
8023 // let primary_message = primary_message?;
8024 // let primary_range =
8025 // buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
8026
8027 // let blocks = display_map
8028 // .insert_blocks(
8029 // diagnostic_group.iter().map(|entry| {
8030 // let diagnostic = entry.diagnostic.clone();
8031 // let message_height = diagnostic.message.lines().count() as u8;
8032 // BlockProperties {
8033 // style: BlockStyle::Fixed,
8034 // position: buffer.anchor_after(entry.range.start),
8035 // height: message_height,
8036 // render: diagnostic_block_renderer(diagnostic, true),
8037 // disposition: BlockDisposition::Below,
8038 // }
8039 // }),
8040 // cx,
8041 // )
8042 // .into_iter()
8043 // .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
8044 // .collect();
8045
8046 // Some(ActiveDiagnosticGroup {
8047 // primary_range,
8048 // primary_message,
8049 // blocks,
8050 // is_valid: true,
8051 // })
8052 // });
8053 // self.active_diagnostics.is_some()
8054 // }
8055
8056 // fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
8057 // if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
8058 // self.display_map.update(cx, |display_map, cx| {
8059 // display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
8060 // });
8061 // cx.notify();
8062 // }
8063 // }
8064
8065 // pub fn set_selections_from_remote(
8066 // &mut self,
8067 // selections: Vec<Selection<Anchor>>,
8068 // pending_selection: Option<Selection<Anchor>>,
8069 // cx: &mut ViewContext<Self>,
8070 // ) {
8071 // let old_cursor_position = self.selections.newest_anchor().head();
8072 // self.selections.change_with(cx, |s| {
8073 // s.select_anchors(selections);
8074 // if let Some(pending_selection) = pending_selection {
8075 // s.set_pending(pending_selection, SelectMode::Character);
8076 // } else {
8077 // s.clear_pending();
8078 // }
8079 // });
8080 // self.selections_did_change(false, &old_cursor_position, cx);
8081 // }
8082
8083 fn push_to_selection_history(&mut self) {
8084 self.selection_history.push(SelectionHistoryEntry {
8085 selections: self.selections.disjoint_anchors(),
8086 select_next_state: self.select_next_state.clone(),
8087 select_prev_state: self.select_prev_state.clone(),
8088 add_selections_state: self.add_selections_state.clone(),
8089 });
8090 }
8091
8092 pub fn transact(
8093 &mut self,
8094 cx: &mut ViewContext<Self>,
8095 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
8096 ) -> Option<TransactionId> {
8097 self.start_transaction_at(Instant::now(), cx);
8098 update(self, cx);
8099 self.end_transaction_at(Instant::now(), cx)
8100 }
8101
8102 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
8103 todo!()
8104 // self.end_selection(cx);
8105 // if let Some(tx_id) = self
8106 // .buffer
8107 // .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
8108 // {
8109 // self.selection_history
8110 // .insert_transaction(tx_id, self.selections.disjoint_anchors());
8111 // }
8112 }
8113
8114 fn end_transaction_at(
8115 &mut self,
8116 now: Instant,
8117 cx: &mut ViewContext<Self>,
8118 ) -> Option<TransactionId> {
8119 todo!()
8120 // if let Some(tx_id) = self
8121 // .buffer
8122 // .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
8123 // {
8124 // if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
8125 // *end_selections = Some(self.selections.disjoint_anchors());
8126 // } else {
8127 // error!("unexpectedly ended a transaction that wasn't started by this editor");
8128 // }
8129
8130 // cx.emit(Event::Edited);
8131 // Some(tx_id)
8132 // } else {
8133 // None
8134 // }
8135 }
8136
8137 // pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
8138 // let mut fold_ranges = Vec::new();
8139
8140 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
8141
8142 // let selections = self.selections.all_adjusted(cx);
8143 // for selection in selections {
8144 // let range = selection.range().sorted();
8145 // let buffer_start_row = range.start.row;
8146
8147 // for row in (0..=range.end.row).rev() {
8148 // let fold_range = display_map.foldable_range(row);
8149
8150 // if let Some(fold_range) = fold_range {
8151 // if fold_range.end.row >= buffer_start_row {
8152 // fold_ranges.push(fold_range);
8153 // if row <= range.start.row {
8154 // break;
8155 // }
8156 // }
8157 // }
8158 // }
8159 // }
8160
8161 // self.fold_ranges(fold_ranges, true, cx);
8162 // }
8163
8164 // pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
8165 // let buffer_row = fold_at.buffer_row;
8166 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
8167
8168 // if let Some(fold_range) = display_map.foldable_range(buffer_row) {
8169 // let autoscroll = self
8170 // .selections
8171 // .all::<Point>(cx)
8172 // .iter()
8173 // .any(|selection| fold_range.overlaps(&selection.range()));
8174
8175 // self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
8176 // }
8177 // }
8178
8179 // pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
8180 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
8181 // let buffer = &display_map.buffer_snapshot;
8182 // let selections = self.selections.all::<Point>(cx);
8183 // let ranges = selections
8184 // .iter()
8185 // .map(|s| {
8186 // let range = s.display_range(&display_map).sorted();
8187 // let mut start = range.start.to_point(&display_map);
8188 // let mut end = range.end.to_point(&display_map);
8189 // start.column = 0;
8190 // end.column = buffer.line_len(end.row);
8191 // start..end
8192 // })
8193 // .collect::<Vec<_>>();
8194
8195 // self.unfold_ranges(ranges, true, true, cx);
8196 // }
8197
8198 // pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
8199 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
8200
8201 // let intersection_range = Point::new(unfold_at.buffer_row, 0)
8202 // ..Point::new(
8203 // unfold_at.buffer_row,
8204 // display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
8205 // );
8206
8207 // let autoscroll = self
8208 // .selections
8209 // .all::<Point>(cx)
8210 // .iter()
8211 // .any(|selection| selection.range().overlaps(&intersection_range));
8212
8213 // self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
8214 // }
8215
8216 // pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
8217 // let selections = self.selections.all::<Point>(cx);
8218 // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
8219 // let line_mode = self.selections.line_mode;
8220 // let ranges = selections.into_iter().map(|s| {
8221 // if line_mode {
8222 // let start = Point::new(s.start.row, 0);
8223 // let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
8224 // start..end
8225 // } else {
8226 // s.start..s.end
8227 // }
8228 // });
8229 // self.fold_ranges(ranges, true, cx);
8230 // }
8231
8232 pub fn fold_ranges<T: ToOffset + Clone>(
8233 &mut self,
8234 ranges: impl IntoIterator<Item = Range<T>>,
8235 auto_scroll: bool,
8236 cx: &mut ViewContext<Self>,
8237 ) {
8238 let mut ranges = ranges.into_iter().peekable();
8239 if ranges.peek().is_some() {
8240 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
8241
8242 if auto_scroll {
8243 self.request_autoscroll(Autoscroll::fit(), cx);
8244 }
8245
8246 cx.notify();
8247 }
8248 }
8249
8250 pub fn unfold_ranges<T: ToOffset + Clone>(
8251 &mut self,
8252 ranges: impl IntoIterator<Item = Range<T>>,
8253 inclusive: bool,
8254 auto_scroll: bool,
8255 cx: &mut ViewContext<Self>,
8256 ) {
8257 let mut ranges = ranges.into_iter().peekable();
8258 if ranges.peek().is_some() {
8259 self.display_map
8260 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
8261 if auto_scroll {
8262 self.request_autoscroll(Autoscroll::fit(), cx);
8263 }
8264
8265 cx.notify();
8266 }
8267 }
8268
8269 // pub fn gutter_hover(
8270 // &mut self,
8271 // GutterHover { hovered }: &GutterHover,
8272 // cx: &mut ViewContext<Self>,
8273 // ) {
8274 // self.gutter_hovered = *hovered;
8275 // cx.notify();
8276 // }
8277
8278 // pub fn insert_blocks(
8279 // &mut self,
8280 // blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
8281 // autoscroll: Option<Autoscroll>,
8282 // cx: &mut ViewContext<Self>,
8283 // ) -> Vec<BlockId> {
8284 // let blocks = self
8285 // .display_map
8286 // .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
8287 // if let Some(autoscroll) = autoscroll {
8288 // self.request_autoscroll(autoscroll, cx);
8289 // }
8290 // blocks
8291 // }
8292
8293 // pub fn replace_blocks(
8294 // &mut self,
8295 // blocks: HashMap<BlockId, RenderBlock>,
8296 // autoscroll: Option<Autoscroll>,
8297 // cx: &mut ViewContext<Self>,
8298 // ) {
8299 // self.display_map
8300 // .update(cx, |display_map, _| display_map.replace_blocks(blocks));
8301 // if let Some(autoscroll) = autoscroll {
8302 // self.request_autoscroll(autoscroll, cx);
8303 // }
8304 // }
8305
8306 pub fn remove_blocks(
8307 &mut self,
8308 block_ids: HashSet<BlockId>,
8309 autoscroll: Option<Autoscroll>,
8310 cx: &mut ViewContext<Self>,
8311 ) {
8312 self.display_map.update(cx, |display_map, cx| {
8313 display_map.remove_blocks(block_ids, cx)
8314 });
8315 if let Some(autoscroll) = autoscroll {
8316 self.request_autoscroll(autoscroll, cx);
8317 }
8318 }
8319
8320 // pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
8321 // self.display_map
8322 // .update(cx, |map, cx| map.snapshot(cx))
8323 // .longest_row()
8324 // }
8325
8326 // pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
8327 // self.display_map
8328 // .update(cx, |map, cx| map.snapshot(cx))
8329 // .max_point()
8330 // }
8331
8332 // pub fn text(&self, cx: &AppContext) -> String {
8333 // self.buffer.read(cx).read(cx).text()
8334 // }
8335
8336 // pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
8337 // self.transact(cx, |this, cx| {
8338 // this.buffer
8339 // .read(cx)
8340 // .as_singleton()
8341 // .expect("you can only call set_text on editors for singleton buffers")
8342 // .update(cx, |buffer, cx| buffer.set_text(text, cx));
8343 // });
8344 // }
8345
8346 // pub fn display_text(&self, cx: &mut AppContext) -> String {
8347 // self.display_map
8348 // .update(cx, |map, cx| map.snapshot(cx))
8349 // .text()
8350 // }
8351
8352 pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
8353 let mut wrap_guides = smallvec::smallvec![];
8354
8355 if self.show_wrap_guides == Some(false) {
8356 return wrap_guides;
8357 }
8358
8359 let settings = self.buffer.read(cx).settings_at(0, cx);
8360 if settings.show_wrap_guides {
8361 if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
8362 wrap_guides.push((soft_wrap as usize, true));
8363 }
8364 wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
8365 }
8366
8367 wrap_guides
8368 }
8369
8370 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
8371 let settings = self.buffer.read(cx).settings_at(0, cx);
8372 let mode = self
8373 .soft_wrap_mode_override
8374 .unwrap_or_else(|| settings.soft_wrap);
8375 match mode {
8376 language_settings::SoftWrap::None => SoftWrap::None,
8377 language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
8378 language_settings::SoftWrap::PreferredLineLength => {
8379 SoftWrap::Column(settings.preferred_line_length)
8380 }
8381 }
8382 }
8383
8384 pub fn set_soft_wrap_mode(
8385 &mut self,
8386 mode: language_settings::SoftWrap,
8387 cx: &mut ViewContext<Self>,
8388 ) {
8389 self.soft_wrap_mode_override = Some(mode);
8390 cx.notify();
8391 }
8392
8393 pub fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
8394 self.display_map
8395 .update(cx, |map, cx| map.set_wrap_width(width, cx))
8396 }
8397
8398 // pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
8399 // if self.soft_wrap_mode_override.is_some() {
8400 // self.soft_wrap_mode_override.take();
8401 // } else {
8402 // let soft_wrap = match self.soft_wrap_mode(cx) {
8403 // SoftWrap::None => language_settings::SoftWrap::EditorWidth,
8404 // SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
8405 // };
8406 // self.soft_wrap_mode_override = Some(soft_wrap);
8407 // }
8408 // cx.notify();
8409 // }
8410
8411 // pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
8412 // self.show_gutter = show_gutter;
8413 // cx.notify();
8414 // }
8415
8416 // pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
8417 // self.show_wrap_guides = Some(show_gutter);
8418 // cx.notify();
8419 // }
8420
8421 // pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
8422 // if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8423 // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8424 // cx.reveal_path(&file.abs_path(cx));
8425 // }
8426 // }
8427 // }
8428
8429 // pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
8430 // if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8431 // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8432 // if let Some(path) = file.abs_path(cx).to_str() {
8433 // cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
8434 // }
8435 // }
8436 // }
8437 // }
8438
8439 // pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
8440 // if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8441 // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8442 // if let Some(path) = file.path().to_str() {
8443 // cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
8444 // }
8445 // }
8446 // }
8447 // }
8448
8449 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
8450 self.highlighted_rows = rows;
8451 }
8452
8453 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
8454 self.highlighted_rows.clone()
8455 }
8456
8457 pub fn highlight_background<T: 'static>(
8458 &mut self,
8459 ranges: Vec<Range<Anchor>>,
8460 color_fetcher: fn(&ThemeColors) -> Hsla,
8461 cx: &mut ViewContext<Self>,
8462 ) {
8463 self.background_highlights
8464 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
8465 cx.notify();
8466 }
8467
8468 // pub fn highlight_inlay_background<T: 'static>(
8469 // &mut self,
8470 // ranges: Vec<InlayHighlight>,
8471 // color_fetcher: fn(&Theme) -> Color,
8472 // cx: &mut ViewContext<Self>,
8473 // ) {
8474 // // TODO: no actual highlights happen for inlays currently, find a way to do that
8475 // self.inlay_background_highlights
8476 // .insert(Some(TypeId::of::<T>()), (color_fetcher, ranges));
8477 // cx.notify();
8478 // }
8479
8480 // pub fn clear_background_highlights<T: 'static>(
8481 // &mut self,
8482 // cx: &mut ViewContext<Self>,
8483 // ) -> Option<BackgroundHighlight> {
8484 // let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
8485 // let inlay_highlights = self
8486 // .inlay_background_highlights
8487 // .remove(&Some(TypeId::of::<T>()));
8488 // if text_highlights.is_some() || inlay_highlights.is_some() {
8489 // cx.notify();
8490 // }
8491 // text_highlights
8492 // }
8493
8494 // #[cfg(feature = "test-support")]
8495 // pub fn all_text_background_highlights(
8496 // &mut self,
8497 // cx: &mut ViewContext<Self>,
8498 // ) -> Vec<(Range<DisplayPoint>, Color)> {
8499 // let snapshot = self.snapshot(cx);
8500 // let buffer = &snapshot.buffer_snapshot;
8501 // let start = buffer.anchor_before(0);
8502 // let end = buffer.anchor_after(buffer.len());
8503 // let theme = theme::current(cx);
8504 // self.background_highlights_in_range(start..end, &snapshot, theme.as_ref())
8505 // }
8506
8507 // fn document_highlights_for_position<'a>(
8508 // &'a self,
8509 // position: Anchor,
8510 // buffer: &'a MultiBufferSnapshot,
8511 // ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
8512 // let read_highlights = self
8513 // .background_highlights
8514 // .get(&TypeId::of::<DocumentHighlightRead>())
8515 // .map(|h| &h.1);
8516 // let write_highlights = self
8517 // .background_highlights
8518 // .get(&TypeId::of::<DocumentHighlightWrite>())
8519 // .map(|h| &h.1);
8520 // let left_position = position.bias_left(buffer);
8521 // let right_position = position.bias_right(buffer);
8522 // read_highlights
8523 // .into_iter()
8524 // .chain(write_highlights)
8525 // .flat_map(move |ranges| {
8526 // let start_ix = match ranges.binary_search_by(|probe| {
8527 // let cmp = probe.end.cmp(&left_position, buffer);
8528 // if cmp.is_ge() {
8529 // Ordering::Greater
8530 // } else {
8531 // Ordering::Less
8532 // }
8533 // }) {
8534 // Ok(i) | Err(i) => i,
8535 // };
8536
8537 // let right_position = right_position.clone();
8538 // ranges[start_ix..]
8539 // .iter()
8540 // .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
8541 // })
8542 // }
8543
8544 pub fn background_highlights_in_range(
8545 &self,
8546 search_range: Range<Anchor>,
8547 display_snapshot: &DisplaySnapshot,
8548 theme: &ThemeColors,
8549 ) -> Vec<(Range<DisplayPoint>, Hsla)> {
8550 let mut results = Vec::new();
8551 for (color_fetcher, ranges) in self.background_highlights.values() {
8552 let color = color_fetcher(theme);
8553 let start_ix = match ranges.binary_search_by(|probe| {
8554 let cmp = probe
8555 .end
8556 .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
8557 if cmp.is_gt() {
8558 Ordering::Greater
8559 } else {
8560 Ordering::Less
8561 }
8562 }) {
8563 Ok(i) | Err(i) => i,
8564 };
8565 for range in &ranges[start_ix..] {
8566 if range
8567 .start
8568 .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
8569 .is_ge()
8570 {
8571 break;
8572 }
8573
8574 let start = range.start.to_display_point(&display_snapshot);
8575 let end = range.end.to_display_point(&display_snapshot);
8576 results.push((start..end, color))
8577 }
8578 }
8579 results
8580 }
8581
8582 // pub fn background_highlight_row_ranges<T: 'static>(
8583 // &self,
8584 // search_range: Range<Anchor>,
8585 // display_snapshot: &DisplaySnapshot,
8586 // count: usize,
8587 // ) -> Vec<RangeInclusive<DisplayPoint>> {
8588 // let mut results = Vec::new();
8589 // let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
8590 // return vec![];
8591 // };
8592
8593 // let start_ix = match ranges.binary_search_by(|probe| {
8594 // let cmp = probe
8595 // .end
8596 // .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
8597 // if cmp.is_gt() {
8598 // Ordering::Greater
8599 // } else {
8600 // Ordering::Less
8601 // }
8602 // }) {
8603 // Ok(i) | Err(i) => i,
8604 // };
8605 // let mut push_region = |start: Option<Point>, end: Option<Point>| {
8606 // if let (Some(start_display), Some(end_display)) = (start, end) {
8607 // results.push(
8608 // start_display.to_display_point(display_snapshot)
8609 // ..=end_display.to_display_point(display_snapshot),
8610 // );
8611 // }
8612 // };
8613 // let mut start_row: Option<Point> = None;
8614 // let mut end_row: Option<Point> = None;
8615 // if ranges.len() > count {
8616 // return Vec::new();
8617 // }
8618 // for range in &ranges[start_ix..] {
8619 // if range
8620 // .start
8621 // .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
8622 // .is_ge()
8623 // {
8624 // break;
8625 // }
8626 // let end = range.end.to_point(&display_snapshot.buffer_snapshot);
8627 // if let Some(current_row) = &end_row {
8628 // if end.row == current_row.row {
8629 // continue;
8630 // }
8631 // }
8632 // let start = range.start.to_point(&display_snapshot.buffer_snapshot);
8633 // if start_row.is_none() {
8634 // assert_eq!(end_row, None);
8635 // start_row = Some(start);
8636 // end_row = Some(end);
8637 // continue;
8638 // }
8639 // if let Some(current_end) = end_row.as_mut() {
8640 // if start.row > current_end.row + 1 {
8641 // push_region(start_row, end_row);
8642 // start_row = Some(start);
8643 // end_row = Some(end);
8644 // } else {
8645 // // Merge two hunks.
8646 // *current_end = end;
8647 // }
8648 // } else {
8649 // unreachable!();
8650 // }
8651 // }
8652 // // We might still have a hunk that was not rendered (if there was a search hit on the last line)
8653 // push_region(start_row, end_row);
8654 // results
8655 // }
8656
8657 // pub fn highlight_text<T: 'static>(
8658 // &mut self,
8659 // ranges: Vec<Range<Anchor>>,
8660 // style: HighlightStyle,
8661 // cx: &mut ViewContext<Self>,
8662 // ) {
8663 // self.display_map.update(cx, |map, _| {
8664 // map.highlight_text(TypeId::of::<T>(), ranges, style)
8665 // });
8666 // cx.notify();
8667 // }
8668
8669 // pub fn highlight_inlays<T: 'static>(
8670 // &mut self,
8671 // highlights: Vec<InlayHighlight>,
8672 // style: HighlightStyle,
8673 // cx: &mut ViewContext<Self>,
8674 // ) {
8675 // self.display_map.update(cx, |map, _| {
8676 // map.highlight_inlays(TypeId::of::<T>(), highlights, style)
8677 // });
8678 // cx.notify();
8679 // }
8680
8681 // pub fn text_highlights<'a, T: 'static>(
8682 // &'a self,
8683 // cx: &'a AppContext,
8684 // ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
8685 // self.display_map.read(cx).text_highlights(TypeId::of::<T>())
8686 // }
8687
8688 pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
8689 let cleared = self
8690 .display_map
8691 .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
8692 if cleared {
8693 cx.notify();
8694 }
8695 }
8696
8697 // pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
8698 // self.blink_manager.read(cx).visible() && self.focused
8699 // }
8700
8701 fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
8702 cx.notify();
8703 }
8704
8705 fn on_buffer_event(
8706 &mut self,
8707 multibuffer: Model<MultiBuffer>,
8708 event: &multi_buffer::Event,
8709 cx: &mut ViewContext<Self>,
8710 ) {
8711 match event {
8712 multi_buffer::Event::Edited {
8713 sigleton_buffer_edited,
8714 } => {
8715 self.refresh_active_diagnostics(cx);
8716 self.refresh_code_actions(cx);
8717 if self.has_active_copilot_suggestion(cx) {
8718 self.update_visible_copilot_suggestion(cx);
8719 }
8720 cx.emit(Event::BufferEdited);
8721
8722 if *sigleton_buffer_edited {
8723 if let Some(project) = &self.project {
8724 let project = project.read(cx);
8725 let languages_affected = multibuffer
8726 .read(cx)
8727 .all_buffers()
8728 .into_iter()
8729 .filter_map(|buffer| {
8730 let buffer = buffer.read(cx);
8731 let language = buffer.language()?;
8732 if project.is_local()
8733 && project.language_servers_for_buffer(buffer, cx).count() == 0
8734 {
8735 None
8736 } else {
8737 Some(language)
8738 }
8739 })
8740 .cloned()
8741 .collect::<HashSet<_>>();
8742 if !languages_affected.is_empty() {
8743 self.refresh_inlay_hints(
8744 InlayHintRefreshReason::BufferEdited(languages_affected),
8745 cx,
8746 );
8747 }
8748 }
8749 }
8750 }
8751 multi_buffer::Event::ExcerptsAdded {
8752 buffer,
8753 predecessor,
8754 excerpts,
8755 } => {
8756 cx.emit(Event::ExcerptsAdded {
8757 buffer: buffer.clone(),
8758 predecessor: *predecessor,
8759 excerpts: excerpts.clone(),
8760 });
8761 self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
8762 }
8763 multi_buffer::Event::ExcerptsRemoved { ids } => {
8764 self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
8765 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
8766 }
8767 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
8768 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
8769 multi_buffer::Event::Saved => cx.emit(Event::Saved),
8770 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
8771 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
8772 multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged),
8773 multi_buffer::Event::Closed => cx.emit(Event::Closed),
8774 multi_buffer::Event::DiagnosticsUpdated => {
8775 self.refresh_active_diagnostics(cx);
8776 }
8777 _ => {}
8778 };
8779 }
8780
8781 fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
8782 cx.notify();
8783 }
8784
8785 fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
8786 self.refresh_copilot_suggestions(true, cx);
8787 self.refresh_inlay_hints(
8788 InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
8789 self.selections.newest_anchor().head(),
8790 &self.buffer.read(cx).snapshot(cx),
8791 cx,
8792 )),
8793 cx,
8794 );
8795 }
8796
8797 // pub fn set_searchable(&mut self, searchable: bool) {
8798 // self.searchable = searchable;
8799 // }
8800
8801 // pub fn searchable(&self) -> bool {
8802 // self.searchable
8803 // }
8804
8805 // fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
8806 // let active_item = workspace.active_item(cx);
8807 // let editor_handle = if let Some(editor) = active_item
8808 // .as_ref()
8809 // .and_then(|item| item.act_as::<Self>(cx))
8810 // {
8811 // editor
8812 // } else {
8813 // cx.propagate_action();
8814 // return;
8815 // };
8816
8817 // let editor = editor_handle.read(cx);
8818 // let buffer = editor.buffer.read(cx);
8819 // if buffer.is_singleton() {
8820 // cx.propagate_action();
8821 // return;
8822 // }
8823
8824 // let mut new_selections_by_buffer = HashMap::default();
8825 // for selection in editor.selections.all::<usize>(cx) {
8826 // for (buffer, mut range, _) in
8827 // buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
8828 // {
8829 // if selection.reversed {
8830 // mem::swap(&mut range.start, &mut range.end);
8831 // }
8832 // new_selections_by_buffer
8833 // .entry(buffer)
8834 // .or_insert(Vec::new())
8835 // .push(range)
8836 // }
8837 // }
8838
8839 // editor_handle.update(cx, |editor, cx| {
8840 // editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
8841 // });
8842 // let pane = workspace.active_pane().clone();
8843 // pane.update(cx, |pane, _| pane.disable_history());
8844
8845 // // We defer the pane interaction because we ourselves are a workspace item
8846 // // and activating a new item causes the pane to call a method on us reentrantly,
8847 // // which panics if we're on the stack.
8848 // cx.defer(move |workspace, cx| {
8849 // for (buffer, ranges) in new_selections_by_buffer.into_iter() {
8850 // let editor = workspace.open_project_item::<Self>(buffer, cx);
8851 // editor.update(cx, |editor, cx| {
8852 // editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
8853 // s.select_ranges(ranges);
8854 // });
8855 // });
8856 // }
8857
8858 // pane.update(cx, |pane, _| pane.enable_history());
8859 // });
8860 // }
8861
8862 // fn jump(
8863 // workspace: &mut Workspace,
8864 // path: ProjectPath,
8865 // position: Point,
8866 // anchor: language::Anchor,
8867 // cx: &mut ViewContext<Workspace>,
8868 // ) {
8869 // let editor = workspace.open_path(path, None, true, cx);
8870 // cx.spawn(|_, mut cx| async move {
8871 // let editor = editor
8872 // .await?
8873 // .downcast::<Editor>()
8874 // .ok_or_else(|| anyhow!("opened item was not an editor"))?
8875 // .downgrade();
8876 // editor.update(&mut cx, |editor, cx| {
8877 // let buffer = editor
8878 // .buffer()
8879 // .read(cx)
8880 // .as_singleton()
8881 // .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
8882 // let buffer = buffer.read(cx);
8883 // let cursor = if buffer.can_resolve(&anchor) {
8884 // language::ToPoint::to_point(&anchor, buffer)
8885 // } else {
8886 // buffer.clip_point(position, Bias::Left)
8887 // };
8888
8889 // let nav_history = editor.nav_history.take();
8890 // editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
8891 // s.select_ranges([cursor..cursor]);
8892 // });
8893 // editor.nav_history = nav_history;
8894
8895 // anyhow::Ok(())
8896 // })??;
8897
8898 // anyhow::Ok(())
8899 // })
8900 // .detach_and_log_err(cx);
8901 // }
8902
8903 // fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
8904 // let snapshot = self.buffer.read(cx).read(cx);
8905 // let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
8906 // Some(
8907 // ranges
8908 // .iter()
8909 // .map(move |range| {
8910 // range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
8911 // })
8912 // .collect(),
8913 // )
8914 // }
8915
8916 // fn selection_replacement_ranges(
8917 // &self,
8918 // range: Range<OffsetUtf16>,
8919 // cx: &AppContext,
8920 // ) -> Vec<Range<OffsetUtf16>> {
8921 // let selections = self.selections.all::<OffsetUtf16>(cx);
8922 // let newest_selection = selections
8923 // .iter()
8924 // .max_by_key(|selection| selection.id)
8925 // .unwrap();
8926 // let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
8927 // let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
8928 // let snapshot = self.buffer.read(cx).read(cx);
8929 // selections
8930 // .into_iter()
8931 // .map(|mut selection| {
8932 // selection.start.0 =
8933 // (selection.start.0 as isize).saturating_add(start_delta) as usize;
8934 // selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
8935 // snapshot.clip_offset_utf16(selection.start, Bias::Left)
8936 // ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
8937 // })
8938 // .collect()
8939 // }
8940
8941 fn report_copilot_event(
8942 &self,
8943 suggestion_id: Option<String>,
8944 suggestion_accepted: bool,
8945 cx: &AppContext,
8946 ) {
8947 let Some(project) = &self.project else { return };
8948
8949 // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
8950 let file_extension = self
8951 .buffer
8952 .read(cx)
8953 .as_singleton()
8954 .and_then(|b| b.read(cx).file())
8955 .and_then(|file| Path::new(file.file_name(cx)).extension())
8956 .and_then(|e| e.to_str())
8957 .map(|a| a.to_string());
8958
8959 let telemetry = project.read(cx).client().telemetry().clone();
8960 let telemetry_settings = *TelemetrySettings::get_global(cx);
8961
8962 let event = ClickhouseEvent::Copilot {
8963 suggestion_id,
8964 suggestion_accepted,
8965 file_extension,
8966 };
8967 telemetry.report_clickhouse_event(event, telemetry_settings);
8968 }
8969
8970 #[cfg(any(test, feature = "test-support"))]
8971 fn report_editor_event(
8972 &self,
8973 _operation: &'static str,
8974 _file_extension: Option<String>,
8975 _cx: &AppContext,
8976 ) {
8977 }
8978
8979 #[cfg(not(any(test, feature = "test-support")))]
8980 fn report_editor_event(
8981 &self,
8982 operation: &'static str,
8983 file_extension: Option<String>,
8984 cx: &AppContext,
8985 ) {
8986 let Some(project) = &self.project else { return };
8987
8988 // If None, we are in a file without an extension
8989 let file = self
8990 .buffer
8991 .read(cx)
8992 .as_singleton()
8993 .and_then(|b| b.read(cx).file());
8994 let file_extension = file_extension.or(file
8995 .as_ref()
8996 .and_then(|file| Path::new(file.file_name(cx)).extension())
8997 .and_then(|e| e.to_str())
8998 .map(|a| a.to_string()));
8999
9000 let vim_mode = cx
9001 .global::<SettingsStore>()
9002 .raw_user_settings()
9003 .get("vim_mode")
9004 == Some(&serde_json::Value::Bool(true));
9005 let telemetry_settings = *TelemetrySettings::get_global(cx);
9006 let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
9007 let copilot_enabled_for_language = self
9008 .buffer
9009 .read(cx)
9010 .settings_at(0, cx)
9011 .show_copilot_suggestions;
9012
9013 let telemetry = project.read(cx).client().telemetry().clone();
9014 let event = ClickhouseEvent::Editor {
9015 file_extension,
9016 vim_mode,
9017 operation,
9018 copilot_enabled,
9019 copilot_enabled_for_language,
9020 };
9021 telemetry.report_clickhouse_event(event, telemetry_settings)
9022 }
9023
9024 // /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
9025 // /// with each line being an array of {text, highlight} objects.
9026 // fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
9027 // let Some(buffer) = self.buffer.read(cx).as_singleton() else {
9028 // return;
9029 // };
9030
9031 // #[derive(Serialize)]
9032 // struct Chunk<'a> {
9033 // text: String,
9034 // highlight: Option<&'a str>,
9035 // }
9036
9037 // let snapshot = buffer.read(cx).snapshot();
9038 // let range = self
9039 // .selected_text_range(cx)
9040 // .and_then(|selected_range| {
9041 // if selected_range.is_empty() {
9042 // None
9043 // } else {
9044 // Some(selected_range)
9045 // }
9046 // })
9047 // .unwrap_or_else(|| 0..snapshot.len());
9048
9049 // let chunks = snapshot.chunks(range, true);
9050 // let mut lines = Vec::new();
9051 // let mut line: VecDeque<Chunk> = VecDeque::new();
9052
9053 // let theme = &theme::current(cx).editor.syntax;
9054
9055 // for chunk in chunks {
9056 // let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
9057 // let mut chunk_lines = chunk.text.split("\n").peekable();
9058 // while let Some(text) = chunk_lines.next() {
9059 // let mut merged_with_last_token = false;
9060 // if let Some(last_token) = line.back_mut() {
9061 // if last_token.highlight == highlight {
9062 // last_token.text.push_str(text);
9063 // merged_with_last_token = true;
9064 // }
9065 // }
9066
9067 // if !merged_with_last_token {
9068 // line.push_back(Chunk {
9069 // text: text.into(),
9070 // highlight,
9071 // });
9072 // }
9073
9074 // if chunk_lines.peek().is_some() {
9075 // if line.len() > 1 && line.front().unwrap().text.is_empty() {
9076 // line.pop_front();
9077 // }
9078 // if line.len() > 1 && line.back().unwrap().text.is_empty() {
9079 // line.pop_back();
9080 // }
9081
9082 // lines.push(mem::take(&mut line));
9083 // }
9084 // }
9085 // }
9086
9087 // let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
9088 // return;
9089 // };
9090 // cx.write_to_clipboard(ClipboardItem::new(lines));
9091 // }
9092
9093 // pub fn inlay_hint_cache(&self) -> &InlayHintCache {
9094 // &self.inlay_hint_cache
9095 // }
9096
9097 // pub fn replay_insert_event(
9098 // &mut self,
9099 // text: &str,
9100 // relative_utf16_range: Option<Range<isize>>,
9101 // cx: &mut ViewContext<Self>,
9102 // ) {
9103 // if !self.input_enabled {
9104 // cx.emit(Event::InputIgnored { text: text.into() });
9105 // return;
9106 // }
9107 // if let Some(relative_utf16_range) = relative_utf16_range {
9108 // let selections = self.selections.all::<OffsetUtf16>(cx);
9109 // self.change_selections(None, cx, |s| {
9110 // let new_ranges = selections.into_iter().map(|range| {
9111 // let start = OffsetUtf16(
9112 // range
9113 // .head()
9114 // .0
9115 // .saturating_add_signed(relative_utf16_range.start),
9116 // );
9117 // let end = OffsetUtf16(
9118 // range
9119 // .head()
9120 // .0
9121 // .saturating_add_signed(relative_utf16_range.end),
9122 // );
9123 // start..end
9124 // });
9125 // s.select_ranges(new_ranges);
9126 // });
9127 // }
9128
9129 // self.handle_input(text, cx);
9130 // }
9131
9132 // pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
9133 // let Some(project) = self.project.as_ref() else {
9134 // return false;
9135 // };
9136 // let project = project.read(cx);
9137
9138 // let mut supports = false;
9139 // self.buffer().read(cx).for_each_buffer(|buffer| {
9140 // if !supports {
9141 // supports = project
9142 // .language_servers_for_buffer(buffer.read(cx), cx)
9143 // .any(
9144 // |(_, server)| match server.capabilities().inlay_hint_provider {
9145 // Some(lsp::OneOf::Left(enabled)) => enabled,
9146 // Some(lsp::OneOf::Right(_)) => true,
9147 // None => false,
9148 // },
9149 // )
9150 // }
9151 // });
9152 // supports
9153 // }
9154}
9155
9156pub trait CollaborationHub {
9157 fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
9158 fn user_participant_indices<'a>(
9159 &self,
9160 cx: &'a AppContext,
9161 ) -> &'a HashMap<u64, ParticipantIndex>;
9162}
9163
9164impl CollaborationHub for Model<Project> {
9165 fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
9166 self.read(cx).collaborators()
9167 }
9168
9169 fn user_participant_indices<'a>(
9170 &self,
9171 cx: &'a AppContext,
9172 ) -> &'a HashMap<u64, ParticipantIndex> {
9173 self.read(cx).user_store().read(cx).participant_indices()
9174 }
9175}
9176
9177fn inlay_hint_settings(
9178 location: Anchor,
9179 snapshot: &MultiBufferSnapshot,
9180 cx: &mut ViewContext<'_, Editor>,
9181) -> InlayHintSettings {
9182 let file = snapshot.file_at(location);
9183 let language = snapshot.language_at(location);
9184 let settings = all_language_settings(file, cx);
9185 settings
9186 .language(language.map(|l| l.name()).as_deref())
9187 .inlay_hints
9188}
9189
9190fn consume_contiguous_rows(
9191 contiguous_row_selections: &mut Vec<Selection<Point>>,
9192 selection: &Selection<Point>,
9193 display_map: &DisplaySnapshot,
9194 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
9195) -> (u32, u32) {
9196 contiguous_row_selections.push(selection.clone());
9197 let start_row = selection.start.row;
9198 let mut end_row = ending_row(selection, display_map);
9199
9200 while let Some(next_selection) = selections.peek() {
9201 if next_selection.start.row <= end_row {
9202 end_row = ending_row(next_selection, display_map);
9203 contiguous_row_selections.push(selections.next().unwrap().clone());
9204 } else {
9205 break;
9206 }
9207 }
9208 (start_row, end_row)
9209}
9210
9211fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
9212 if next_selection.end.column > 0 || next_selection.is_empty() {
9213 display_map.next_line_boundary(next_selection.end).0.row + 1
9214 } else {
9215 next_selection.end.row
9216 }
9217}
9218
9219impl EditorSnapshot {
9220 pub fn remote_selections_in_range<'a>(
9221 &'a self,
9222 range: &'a Range<Anchor>,
9223 collaboration_hub: &dyn CollaborationHub,
9224 cx: &'a AppContext,
9225 ) -> impl 'a + Iterator<Item = RemoteSelection> {
9226 let participant_indices = collaboration_hub.user_participant_indices(cx);
9227 let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
9228 let collaborators_by_replica_id = collaborators_by_peer_id
9229 .iter()
9230 .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
9231 .collect::<HashMap<_, _>>();
9232 self.buffer_snapshot
9233 .remote_selections_in_range(range)
9234 .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
9235 let collaborator = collaborators_by_replica_id.get(&replica_id)?;
9236 let participant_index = participant_indices.get(&collaborator.user_id).copied();
9237 Some(RemoteSelection {
9238 replica_id,
9239 selection,
9240 cursor_shape,
9241 line_mode,
9242 participant_index,
9243 peer_id: collaborator.peer_id,
9244 })
9245 })
9246 }
9247
9248 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
9249 self.display_snapshot.buffer_snapshot.language_at(position)
9250 }
9251
9252 pub fn is_focused(&self) -> bool {
9253 self.is_focused
9254 }
9255
9256 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
9257 self.placeholder_text.as_ref()
9258 }
9259
9260 pub fn scroll_position(&self) -> gpui::Point<f32> {
9261 self.scroll_anchor.scroll_position(&self.display_snapshot)
9262 }
9263}
9264
9265impl Deref for EditorSnapshot {
9266 type Target = DisplaySnapshot;
9267
9268 fn deref(&self) -> &Self::Target {
9269 &self.display_snapshot
9270 }
9271}
9272
9273#[derive(Clone, Debug, PartialEq, Eq)]
9274pub enum Event {
9275 InputIgnored {
9276 text: Arc<str>,
9277 },
9278 InputHandled {
9279 utf16_range_to_replace: Option<Range<isize>>,
9280 text: Arc<str>,
9281 },
9282 ExcerptsAdded {
9283 buffer: Model<Buffer>,
9284 predecessor: ExcerptId,
9285 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
9286 },
9287 ExcerptsRemoved {
9288 ids: Vec<ExcerptId>,
9289 },
9290 BufferEdited,
9291 Edited,
9292 Reparsed,
9293 Focused,
9294 Blurred,
9295 DirtyChanged,
9296 Saved,
9297 TitleChanged,
9298 DiffBaseChanged,
9299 SelectionsChanged {
9300 local: bool,
9301 },
9302 ScrollPositionChanged {
9303 local: bool,
9304 autoscroll: bool,
9305 },
9306 Closed,
9307}
9308
9309pub struct EditorFocused(pub View<Editor>);
9310pub struct EditorBlurred(pub View<Editor>);
9311pub struct EditorReleased(pub WeakView<Editor>);
9312
9313// impl Entity for Editor {
9314// type Event = Event;
9315
9316// fn release(&mut self, cx: &mut AppContext) {
9317// cx.emit_global(EditorReleased(self.handle.clone()));
9318// }
9319// }
9320//
9321impl EventEmitter for Editor {
9322 type Event = Event;
9323}
9324
9325impl Render for Editor {
9326 type Element = EditorElement;
9327
9328 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
9329 EditorElement::new(EditorStyle {
9330 local_player: cx.theme().players().local(),
9331 text: cx.text_style(),
9332 line_height_scalar: 1.,
9333 theme_id: 0,
9334 })
9335 }
9336}
9337
9338// impl View for Editor {
9339// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
9340// let style = self.style(cx);
9341// let font_changed = self.display_map.update(cx, |map, cx| {
9342// map.set_fold_ellipses_color(style.folds.ellipses.text_color);
9343// map.set_font_with_size(style.text.font_id, style.text.font_size, cx)
9344// });
9345
9346// if font_changed {
9347// cx.defer(move |editor, cx: &mut ViewContext<Editor>| {
9348// hide_hover(editor, cx);
9349// hide_link_definition(editor, cx);
9350// });
9351// }
9352
9353// Stack::new()
9354// .with_child(EditorElement::new(style.clone()))
9355// .with_child(ChildView::new(&self.mouse_context_menu, cx))
9356// .into_any()
9357// }
9358
9359// fn ui_name() -> &'static str {
9360// "Editor"
9361// }
9362
9363// fn focus_in(&mut self, focused: AnyView, cx: &mut ViewContext<Self>) {
9364// if cx.is_self_focused() {
9365// let focused_event = EditorFocused(cx.handle());
9366// cx.emit(Event::Focused);
9367// cx.emit_global(focused_event);
9368// }
9369// if let Some(rename) = self.pending_rename.as_ref() {
9370// cx.focus(&rename.editor);
9371// } else if cx.is_self_focused() || !focused.is::<Editor>() {
9372// if !self.focused {
9373// self.blink_manager.update(cx, BlinkManager::enable);
9374// }
9375// self.focused = true;
9376// self.buffer.update(cx, |buffer, cx| {
9377// buffer.finalize_last_transaction(cx);
9378// if self.leader_peer_id.is_none() {
9379// buffer.set_active_selections(
9380// &self.selections.disjoint_anchors(),
9381// self.selections.line_mode,
9382// self.cursor_shape,
9383// cx,
9384// );
9385// }
9386// });
9387// }
9388// }
9389
9390// fn focus_out(&mut self, _: AnyView, cx: &mut ViewContext<Self>) {
9391// let blurred_event = EditorBlurred(cx.handle());
9392// cx.emit_global(blurred_event);
9393// self.focused = false;
9394// self.blink_manager.update(cx, BlinkManager::disable);
9395// self.buffer
9396// .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
9397// self.hide_context_menu(cx);
9398// hide_hover(self, cx);
9399// cx.emit(Event::Blurred);
9400// cx.notify();
9401// }
9402
9403// fn modifiers_changed(
9404// &mut self,
9405// event: &gpui::platform::ModifiersChangedEvent,
9406// cx: &mut ViewContext<Self>,
9407// ) -> bool {
9408// let pending_selection = self.has_pending_selection();
9409
9410// if let Some(point) = &self.link_go_to_definition_state.last_trigger_point {
9411// if event.cmd && !pending_selection {
9412// let point = point.clone();
9413// let snapshot = self.snapshot(cx);
9414// let kind = point.definition_kind(event.shift);
9415
9416// show_link_definition(kind, self, point, snapshot, cx);
9417// return false;
9418// }
9419// }
9420
9421// {
9422// if self.link_go_to_definition_state.symbol_range.is_some()
9423// || !self.link_go_to_definition_state.definitions.is_empty()
9424// {
9425// self.link_go_to_definition_state.symbol_range.take();
9426// self.link_go_to_definition_state.definitions.clear();
9427// cx.notify();
9428// }
9429
9430// self.link_go_to_definition_state.task = None;
9431
9432// self.clear_highlights::<LinkGoToDefinitionState>(cx);
9433// }
9434
9435// false
9436// }
9437
9438// fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) {
9439// Self::reset_to_default_keymap_context(keymap);
9440// let mode = match self.mode {
9441// EditorMode::SingleLine => "single_line",
9442// EditorMode::AutoHeight { .. } => "auto_height",
9443// EditorMode::Full => "full",
9444// };
9445// keymap.add_key("mode", mode);
9446// if self.pending_rename.is_some() {
9447// keymap.add_identifier("renaming");
9448// }
9449// if self.context_menu_visible() {
9450// match self.context_menu.read().as_ref() {
9451// Some(ContextMenu::Completions(_)) => {
9452// keymap.add_identifier("menu");
9453// keymap.add_identifier("showing_completions")
9454// }
9455// Some(ContextMenu::CodeActions(_)) => {
9456// keymap.add_identifier("menu");
9457// keymap.add_identifier("showing_code_actions")
9458// }
9459// None => {}
9460// }
9461// }
9462
9463// for layer in self.keymap_context_layers.values() {
9464// keymap.extend(layer);
9465// }
9466
9467// if let Some(extension) = self
9468// .buffer
9469// .read(cx)
9470// .as_singleton()
9471// .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
9472// {
9473// keymap.add_key("extension", extension.to_string());
9474// }
9475// }
9476
9477// fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
9478// Some(
9479// self.buffer
9480// .read(cx)
9481// .read(cx)
9482// .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
9483// .collect(),
9484// )
9485// }
9486
9487// fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
9488// // Prevent the IME menu from appearing when holding down an alphabetic key
9489// // while input is disabled.
9490// if !self.input_enabled {
9491// return None;
9492// }
9493
9494// let range = self.selections.newest::<OffsetUtf16>(cx).range();
9495// Some(range.start.0..range.end.0)
9496// }
9497
9498// fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
9499// let snapshot = self.buffer.read(cx).read(cx);
9500// let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
9501// Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
9502// }
9503
9504// fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
9505// self.clear_highlights::<InputComposition>(cx);
9506// self.ime_transaction.take();
9507// }
9508
9509// fn replace_text_in_range(
9510// &mut self,
9511// range_utf16: Option<Range<usize>>,
9512// text: &str,
9513// cx: &mut ViewContext<Self>,
9514// ) {
9515// if !self.input_enabled {
9516// cx.emit(Event::InputIgnored { text: text.into() });
9517// return;
9518// }
9519
9520// self.transact(cx, |this, cx| {
9521// let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
9522// let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
9523// Some(this.selection_replacement_ranges(range_utf16, cx))
9524// } else {
9525// this.marked_text_ranges(cx)
9526// };
9527
9528// let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
9529// let newest_selection_id = this.selections.newest_anchor().id;
9530// this.selections
9531// .all::<OffsetUtf16>(cx)
9532// .iter()
9533// .zip(ranges_to_replace.iter())
9534// .find_map(|(selection, range)| {
9535// if selection.id == newest_selection_id {
9536// Some(
9537// (range.start.0 as isize - selection.head().0 as isize)
9538// ..(range.end.0 as isize - selection.head().0 as isize),
9539// )
9540// } else {
9541// None
9542// }
9543// })
9544// });
9545
9546// cx.emit(Event::InputHandled {
9547// utf16_range_to_replace: range_to_replace,
9548// text: text.into(),
9549// });
9550
9551// if let Some(new_selected_ranges) = new_selected_ranges {
9552// this.change_selections(None, cx, |selections| {
9553// selections.select_ranges(new_selected_ranges)
9554// });
9555// }
9556
9557// this.handle_input(text, cx);
9558// });
9559
9560// if let Some(transaction) = self.ime_transaction {
9561// self.buffer.update(cx, |buffer, cx| {
9562// buffer.group_until_transaction(transaction, cx);
9563// });
9564// }
9565
9566// self.unmark_text(cx);
9567// }
9568
9569// fn replace_and_mark_text_in_range(
9570// &mut self,
9571// range_utf16: Option<Range<usize>>,
9572// text: &str,
9573// new_selected_range_utf16: Option<Range<usize>>,
9574// cx: &mut ViewContext<Self>,
9575// ) {
9576// if !self.input_enabled {
9577// cx.emit(Event::InputIgnored { text: text.into() });
9578// return;
9579// }
9580
9581// let transaction = self.transact(cx, |this, cx| {
9582// let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
9583// let snapshot = this.buffer.read(cx).read(cx);
9584// if let Some(relative_range_utf16) = range_utf16.as_ref() {
9585// for marked_range in &mut marked_ranges {
9586// marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
9587// marked_range.start.0 += relative_range_utf16.start;
9588// marked_range.start =
9589// snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
9590// marked_range.end =
9591// snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
9592// }
9593// }
9594// Some(marked_ranges)
9595// } else if let Some(range_utf16) = range_utf16 {
9596// let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
9597// Some(this.selection_replacement_ranges(range_utf16, cx))
9598// } else {
9599// None
9600// };
9601
9602// let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
9603// let newest_selection_id = this.selections.newest_anchor().id;
9604// this.selections
9605// .all::<OffsetUtf16>(cx)
9606// .iter()
9607// .zip(ranges_to_replace.iter())
9608// .find_map(|(selection, range)| {
9609// if selection.id == newest_selection_id {
9610// Some(
9611// (range.start.0 as isize - selection.head().0 as isize)
9612// ..(range.end.0 as isize - selection.head().0 as isize),
9613// )
9614// } else {
9615// None
9616// }
9617// })
9618// });
9619
9620// cx.emit(Event::InputHandled {
9621// utf16_range_to_replace: range_to_replace,
9622// text: text.into(),
9623// });
9624
9625// if let Some(ranges) = ranges_to_replace {
9626// this.change_selections(None, cx, |s| s.select_ranges(ranges));
9627// }
9628
9629// let marked_ranges = {
9630// let snapshot = this.buffer.read(cx).read(cx);
9631// this.selections
9632// .disjoint_anchors()
9633// .iter()
9634// .map(|selection| {
9635// selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
9636// })
9637// .collect::<Vec<_>>()
9638// };
9639
9640// if text.is_empty() {
9641// this.unmark_text(cx);
9642// } else {
9643// this.highlight_text::<InputComposition>(
9644// marked_ranges.clone(),
9645// this.style(cx).composition_mark,
9646// cx,
9647// );
9648// }
9649
9650// this.handle_input(text, cx);
9651
9652// if let Some(new_selected_range) = new_selected_range_utf16 {
9653// let snapshot = this.buffer.read(cx).read(cx);
9654// let new_selected_ranges = marked_ranges
9655// .into_iter()
9656// .map(|marked_range| {
9657// let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
9658// let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
9659// let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
9660// snapshot.clip_offset_utf16(new_start, Bias::Left)
9661// ..snapshot.clip_offset_utf16(new_end, Bias::Right)
9662// })
9663// .collect::<Vec<_>>();
9664
9665// drop(snapshot);
9666// this.change_selections(None, cx, |selections| {
9667// selections.select_ranges(new_selected_ranges)
9668// });
9669// }
9670// });
9671
9672// self.ime_transaction = self.ime_transaction.or(transaction);
9673// if let Some(transaction) = self.ime_transaction {
9674// self.buffer.update(cx, |buffer, cx| {
9675// buffer.group_until_transaction(transaction, cx);
9676// });
9677// }
9678
9679// if self.text_highlights::<InputComposition>(cx).is_none() {
9680// self.ime_transaction.take();
9681// }
9682// }
9683// }
9684
9685// fn build_style(
9686// settings: &ThemeSettings,
9687// get_field_editor_theme: Option<&GetFieldEditorTheme>,
9688// override_text_style: Option<&OverrideTextStyle>,
9689// cx: &mut AppContext,
9690// ) -> EditorStyle {
9691// let font_cache = cx.font_cache();
9692// let line_height_scalar = settings.line_height();
9693// let theme_id = settings.theme.meta.id;
9694// let mut theme = settings.theme.editor.clone();
9695// let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
9696// let field_editor_theme = get_field_editor_theme(&settings.theme);
9697// theme.text_color = field_editor_theme.text.color;
9698// theme.selection = field_editor_theme.selection;
9699// theme.background = field_editor_theme
9700// .container
9701// .background_color
9702// .unwrap_or_default();
9703// EditorStyle {
9704// text: field_editor_theme.text,
9705// placeholder_text: field_editor_theme.placeholder_text,
9706// line_height_scalar,
9707// theme,
9708// theme_id,
9709// }
9710// } else {
9711// todo!();
9712// // let font_family_id = settings.buffer_font_family;
9713// // let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
9714// // let font_properties = Default::default();
9715// // let font_id = font_cache
9716// // .select_font(font_family_id, &font_properties)
9717// // .unwrap();
9718// // let font_size = settings.buffer_font_size(cx);
9719// // EditorStyle {
9720// // text: TextStyle {
9721// // color: settings.theme.editor.text_color,
9722// // font_family_name,
9723// // font_family_id,
9724// // font_id,
9725// // font_size,
9726// // font_properties,
9727// // underline: Default::default(),
9728// // soft_wrap: false,
9729// // },
9730// // placeholder_text: None,
9731// // line_height_scalar,
9732// // theme,
9733// // theme_id,
9734// // }
9735// };
9736
9737// if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
9738// if let Some(highlighted) = style
9739// .text
9740// .clone()
9741// .highlight(highlight_style, font_cache)
9742// .log_err()
9743// {
9744// style.text = highlighted;
9745// }
9746// }
9747
9748// style
9749// }
9750
9751trait SelectionExt {
9752 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
9753 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
9754 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
9755 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
9756 -> Range<u32>;
9757}
9758
9759impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
9760 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
9761 let start = self.start.to_point(buffer);
9762 let end = self.end.to_point(buffer);
9763 if self.reversed {
9764 end..start
9765 } else {
9766 start..end
9767 }
9768 }
9769
9770 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
9771 let start = self.start.to_offset(buffer);
9772 let end = self.end.to_offset(buffer);
9773 if self.reversed {
9774 end..start
9775 } else {
9776 start..end
9777 }
9778 }
9779
9780 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
9781 let start = self
9782 .start
9783 .to_point(&map.buffer_snapshot)
9784 .to_display_point(map);
9785 let end = self
9786 .end
9787 .to_point(&map.buffer_snapshot)
9788 .to_display_point(map);
9789 if self.reversed {
9790 end..start
9791 } else {
9792 start..end
9793 }
9794 }
9795
9796 fn spanned_rows(
9797 &self,
9798 include_end_if_at_line_start: bool,
9799 map: &DisplaySnapshot,
9800 ) -> Range<u32> {
9801 let start = self.start.to_point(&map.buffer_snapshot);
9802 let mut end = self.end.to_point(&map.buffer_snapshot);
9803 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
9804 end.row -= 1;
9805 }
9806
9807 let buffer_start = map.prev_line_boundary(start).0;
9808 let buffer_end = map.next_line_boundary(end).0;
9809 buffer_start.row..buffer_end.row + 1
9810 }
9811}
9812
9813impl<T: InvalidationRegion> InvalidationStack<T> {
9814 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
9815 where
9816 S: Clone + ToOffset,
9817 {
9818 while let Some(region) = self.last() {
9819 let all_selections_inside_invalidation_ranges =
9820 if selections.len() == region.ranges().len() {
9821 selections
9822 .iter()
9823 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
9824 .all(|(selection, invalidation_range)| {
9825 let head = selection.head().to_offset(buffer);
9826 invalidation_range.start <= head && invalidation_range.end >= head
9827 })
9828 } else {
9829 false
9830 };
9831
9832 if all_selections_inside_invalidation_ranges {
9833 break;
9834 } else {
9835 self.pop();
9836 }
9837 }
9838 }
9839}
9840
9841impl<T> Default for InvalidationStack<T> {
9842 fn default() -> Self {
9843 Self(Default::default())
9844 }
9845}
9846
9847impl<T> Deref for InvalidationStack<T> {
9848 type Target = Vec<T>;
9849
9850 fn deref(&self) -> &Self::Target {
9851 &self.0
9852 }
9853}
9854
9855impl<T> DerefMut for InvalidationStack<T> {
9856 fn deref_mut(&mut self) -> &mut Self::Target {
9857 &mut self.0
9858 }
9859}
9860
9861impl InvalidationRegion for SnippetState {
9862 fn ranges(&self) -> &[Range<Anchor>] {
9863 &self.ranges[self.active_index]
9864 }
9865}
9866
9867// impl Deref for EditorStyle {
9868// type Target = theme::Editor;
9869
9870// fn deref(&self) -> &Self::Target {
9871// &self.theme
9872// }
9873// }
9874
9875pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
9876 let mut highlighted_lines = Vec::new();
9877
9878 for (index, line) in diagnostic.message.lines().enumerate() {
9879 let line = match &diagnostic.source {
9880 Some(source) if index == 0 => {
9881 let source_highlight = Vec::from_iter(0..source.len());
9882 highlight_diagnostic_message(source_highlight, &format!("{source}: {line}"))
9883 }
9884
9885 _ => highlight_diagnostic_message(Vec::new(), line),
9886 };
9887 highlighted_lines.push(line);
9888 }
9889 let message = diagnostic.message;
9890 Arc::new(move |cx: &mut BlockContext| {
9891 todo!()
9892 // let message = message.clone();
9893 // let settings = ThemeSettings::get_global(cx);
9894 // let tooltip_style = settings.theme.tooltip.clone();
9895 // let theme = &settings.theme.editor;
9896 // let style = diagnostic_style(diagnostic.severity, is_valid, theme);
9897 // let font_size = (style.text_scale_factor * settings.buffer_font_size(cx)).round();
9898 // let anchor_x = cx.anchor_x;
9899 // enum BlockContextToolip {}
9900 // MouseEventHandler::new::<BlockContext, _>(cx.block_id, cx, |_, _| {
9901 // Flex::column()
9902 // .with_children(highlighted_lines.iter().map(|(line, highlights)| {
9903 // Label::new(
9904 // line.clone(),
9905 // style.message.clone().with_font_size(font_size),
9906 // )
9907 // .with_highlights(highlights.clone())
9908 // .contained()
9909 // .with_margin_left(anchor_x)
9910 // }))
9911 // .aligned()
9912 // .left()
9913 // .into_any()
9914 // })
9915 // .with_cursor_style(CursorStyle::PointingHand)
9916 // .on_click(MouseButton::Left, move |_, _, cx| {
9917 // cx.write_to_clipboard(ClipboardItem::new(message.clone()));
9918 // })
9919 // // We really need to rethink this ID system...
9920 // .with_tooltip::<BlockContextToolip>(
9921 // cx.block_id,
9922 // "Copy diagnostic message",
9923 // None,
9924 // tooltip_style,
9925 // cx,
9926 // )
9927 // .into_any()
9928 })
9929}
9930
9931pub fn highlight_diagnostic_message(
9932 initial_highlights: Vec<usize>,
9933 message: &str,
9934) -> (String, Vec<usize>) {
9935 let mut message_without_backticks = String::new();
9936 let mut prev_offset = 0;
9937 let mut inside_block = false;
9938 let mut highlights = initial_highlights;
9939 for (match_ix, (offset, _)) in message
9940 .match_indices('`')
9941 .chain([(message.len(), "")])
9942 .enumerate()
9943 {
9944 message_without_backticks.push_str(&message[prev_offset..offset]);
9945 if inside_block {
9946 highlights.extend(prev_offset - match_ix..offset - match_ix);
9947 }
9948
9949 inside_block = !inside_block;
9950 prev_offset = offset + 1;
9951 }
9952
9953 (message_without_backticks, highlights)
9954}
9955
9956pub fn diagnostic_style(severity: DiagnosticSeverity, valid: bool, theme: &ThemeVariant) -> Hsla {
9957 match (severity, valid) {
9958 (DiagnosticSeverity::ERROR, true) => theme.status().error,
9959 (DiagnosticSeverity::ERROR, false) => theme.status().error,
9960 (DiagnosticSeverity::WARNING, true) => theme.status().warning,
9961 (DiagnosticSeverity::WARNING, false) => theme.status().warning,
9962 (DiagnosticSeverity::INFORMATION, true) => theme.status().info,
9963 (DiagnosticSeverity::INFORMATION, false) => theme.status().info,
9964 (DiagnosticSeverity::HINT, true) => theme.status().info,
9965 (DiagnosticSeverity::HINT, false) => theme.status().info,
9966 _ => theme.status().ignored,
9967 }
9968}
9969
9970// pub fn combine_syntax_and_fuzzy_match_highlights(
9971// text: &str,
9972// default_style: HighlightStyle,
9973// syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
9974// match_indices: &[usize],
9975// ) -> Vec<(Range<usize>, HighlightStyle)> {
9976// let mut result = Vec::new();
9977// let mut match_indices = match_indices.iter().copied().peekable();
9978
9979// for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
9980// {
9981// syntax_highlight.weight = None;
9982
9983// // Add highlights for any fuzzy match characters before the next
9984// // syntax highlight range.
9985// while let Some(&match_index) = match_indices.peek() {
9986// if match_index >= range.start {
9987// break;
9988// }
9989// match_indices.next();
9990// let end_index = char_ix_after(match_index, text);
9991// let mut match_style = default_style;
9992// match_style.weight = Some(FontWeight::BOLD);
9993// result.push((match_index..end_index, match_style));
9994// }
9995
9996// if range.start == usize::MAX {
9997// break;
9998// }
9999
10000// // Add highlights for any fuzzy match characters within the
10001// // syntax highlight range.
10002// let mut offset = range.start;
10003// while let Some(&match_index) = match_indices.peek() {
10004// if match_index >= range.end {
10005// break;
10006// }
10007
10008// match_indices.next();
10009// if match_index > offset {
10010// result.push((offset..match_index, syntax_highlight));
10011// }
10012
10013// let mut end_index = char_ix_after(match_index, text);
10014// while let Some(&next_match_index) = match_indices.peek() {
10015// if next_match_index == end_index && next_match_index < range.end {
10016// end_index = char_ix_after(next_match_index, text);
10017// match_indices.next();
10018// } else {
10019// break;
10020// }
10021// }
10022
10023// let mut match_style = syntax_highlight;
10024// match_style.weight = Some(FontWeight::BOLD);
10025// result.push((match_index..end_index, match_style));
10026// offset = end_index;
10027// }
10028
10029// if offset < range.end {
10030// result.push((offset..range.end, syntax_highlight));
10031// }
10032// }
10033
10034// fn char_ix_after(ix: usize, text: &str) -> usize {
10035// ix + text[ix..].chars().next().unwrap().len_utf8()
10036// }
10037
10038// result
10039// }
10040
10041// pub fn styled_runs_for_code_label<'a>(
10042// label: &'a CodeLabel,
10043// syntax_theme: &'a theme::SyntaxTheme,
10044// ) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
10045// let fade_out = HighlightStyle {
10046// fade_out: Some(0.35),
10047// ..Default::default()
10048// };
10049
10050// let mut prev_end = label.filter_range.end;
10051// label
10052// .runs
10053// .iter()
10054// .enumerate()
10055// .flat_map(move |(ix, (range, highlight_id))| {
10056// let style = if let Some(style) = highlight_id.style(syntax_theme) {
10057// style
10058// } else {
10059// return Default::default();
10060// };
10061// let mut muted_style = style;
10062// muted_style.highlight(fade_out);
10063
10064// let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
10065// if range.start >= label.filter_range.end {
10066// if range.start > prev_end {
10067// runs.push((prev_end..range.start, fade_out));
10068// }
10069// runs.push((range.clone(), muted_style));
10070// } else if range.end <= label.filter_range.end {
10071// runs.push((range.clone(), style));
10072// } else {
10073// runs.push((range.start..label.filter_range.end, style));
10074// runs.push((label.filter_range.end..range.end, muted_style));
10075// }
10076// prev_end = cmp::max(prev_end, range.end);
10077
10078// if ix + 1 == label.runs.len() && label.text.len() > prev_end {
10079// runs.push((prev_end..label.text.len(), fade_out));
10080// }
10081
10082// runs
10083// })
10084
10085pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
10086 let mut index = 0;
10087 let mut codepoints = text.char_indices().peekable();
10088
10089 std::iter::from_fn(move || {
10090 let start_index = index;
10091 while let Some((new_index, codepoint)) = codepoints.next() {
10092 index = new_index + codepoint.len_utf8();
10093 let current_upper = codepoint.is_uppercase();
10094 let next_upper = codepoints
10095 .peek()
10096 .map(|(_, c)| c.is_uppercase())
10097 .unwrap_or(false);
10098
10099 if !current_upper && next_upper {
10100 return Some(&text[start_index..index]);
10101 }
10102 }
10103
10104 index = text.len();
10105 if start_index < text.len() {
10106 return Some(&text[start_index..]);
10107 }
10108 None
10109 })
10110 .flat_map(|word| word.split_inclusive('_'))
10111 .flat_map(|word| word.split_inclusive('-'))
10112}
10113
10114trait RangeToAnchorExt {
10115 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
10116}
10117
10118impl<T: ToOffset> RangeToAnchorExt for Range<T> {
10119 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
10120 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
10121 }
10122}