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