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