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