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