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