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