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