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