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