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