@@ -20,12 +20,14 @@ pub mod selections_collection;
mod editor_tests;
#[cfg(any(test, feature = "test-support"))]
pub mod test;
+use ::git::diff::DiffHunk;
use aho_corasick::AhoCorasick;
use anyhow::{Context as _, Result};
use blink_manager::BlinkManager;
use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings};
use clock::ReplicaId;
-use collections::{BTreeMap, HashMap, HashSet, VecDeque};
+use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
+use convert_case::{Case, Casing};
use copilot::Copilot;
pub use display_map::DisplayPoint;
use display_map::*;
@@ -35,11 +37,13 @@ pub use element::{
};
use futures::FutureExt;
use fuzzy::{StringMatch, StringMatchCandidate};
+use git::diff_hunk_to_display;
use gpui::{
- actions, div, px, relative, AnyElement, AppContext, BackgroundExecutor, Context,
- DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle, FontStyle, FontWeight,
- HighlightStyle, Hsla, InputHandler, Model, Pixels, PlatformInputHandler, Render, Styled,
- Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView, WindowContext,
+ action, actions, div, px, relative, AnyElement, AppContext, BackgroundExecutor, ClipboardItem,
+ Context, DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle, FontStyle,
+ FontWeight, HighlightStyle, Hsla, InputHandler, Model, Pixels, PlatformInputHandler, Render,
+ Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView,
+ WindowContext,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@@ -50,8 +54,8 @@ pub use language::{char_kind, CharKind};
use language::{
language_settings::{self, all_language_settings, InlayHintSettings},
point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, Completion, CursorShape,
- Diagnostic, Language, LanguageRegistry, LanguageServerName, OffsetRangeExt, Point, Selection,
- SelectionGoal, TransactionId,
+ Diagnostic, IndentKind, IndentSize, Language, LanguageRegistry, LanguageServerName,
+ OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
};
use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState};
use lsp::{DiagnosticSeverity, Documentation, LanguageServerId};
@@ -64,6 +68,7 @@ pub use multi_buffer::{
use ordered_float::OrderedFloat;
use parking_lot::RwLock;
use project::{FormatTrigger, Location, Project};
+use rand::prelude::*;
use rpc::proto::*;
use scroll::{
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
@@ -72,11 +77,14 @@ use selections_collection::{resolve_multiple, MutableSelectionsCollection, Selec
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use smallvec::SmallVec;
+use snippet::Snippet;
use std::{
any::TypeId,
borrow::Cow,
cmp::{self, Ordering, Reverse},
- ops::{ControlFlow, Deref, DerefMut, Range},
+ mem,
+ num::NonZeroU32,
+ ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
path::Path,
sync::Arc,
time::{Duration, Instant},
@@ -165,83 +173,83 @@ pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
// // .with_soft_wrap(true)
// }
-#[derive(Clone, Deserialize, PartialEq, Default)]
+#[action]
pub struct SelectNext {
#[serde(default)]
pub replace_newest: bool,
}
-#[derive(Clone, Deserialize, PartialEq, Default)]
+#[action]
pub struct SelectPrevious {
#[serde(default)]
pub replace_newest: bool,
}
-#[derive(Clone, Deserialize, PartialEq, Default)]
+#[action]
pub struct SelectAllMatches {
#[serde(default)]
pub replace_newest: bool,
}
-#[derive(Clone, Deserialize, PartialEq)]
+#[action]
pub struct SelectToBeginningOfLine {
#[serde(default)]
stop_at_soft_wraps: bool,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct MovePageUp {
#[serde(default)]
center_cursor: bool,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct MovePageDown {
#[serde(default)]
center_cursor: bool,
}
-#[derive(Clone, Deserialize, PartialEq)]
+#[action]
pub struct SelectToEndOfLine {
#[serde(default)]
stop_at_soft_wraps: bool,
}
-#[derive(Clone, Deserialize, PartialEq)]
+#[action]
pub struct ToggleCodeActions {
#[serde(default)]
pub deployed_from_indicator: bool,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct ConfirmCompletion {
#[serde(default)]
pub item_ix: Option<usize>,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct ConfirmCodeAction {
#[serde(default)]
pub item_ix: Option<usize>,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct ToggleComments {
#[serde(default)]
pub advance_downwards: bool,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct FoldAt {
pub buffer_row: u32,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct UnfoldAt {
pub buffer_row: u32,
}
-#[derive(Clone, Default, Deserialize, PartialEq)]
+#[action]
pub struct GutterHover {
pub hovered: bool,
}
@@ -262,113 +270,121 @@ impl InlayId {
}
actions!(
- Cancel,
+ AddSelectionAbove,
+ AddSelectionBelow,
Backspace,
+ Cancel,
+ ConfirmRename,
+ ContextMenuFirst,
+ ContextMenuLast,
+ ContextMenuNext,
+ ContextMenuPrev,
+ ConvertToKebabCase,
+ ConvertToLowerCamelCase,
+ ConvertToLowerCase,
+ ConvertToSnakeCase,
+ ConvertToTitleCase,
+ ConvertToUpperCamelCase,
+ ConvertToUpperCase,
+ Copy,
+ CopyHighlightJson,
+ CopyPath,
+ CopyRelativePath,
+ Cut,
+ CutToEndOfLine,
Delete,
- Newline,
- NewlineAbove,
- NewlineBelow,
- GoToDiagnostic,
- GoToPrevDiagnostic,
- GoToHunk,
- GoToPrevHunk,
- Indent,
- Outdent,
DeleteLine,
- DeleteToPreviousWordStart,
- DeleteToPreviousSubwordStart,
- DeleteToNextWordEnd,
- DeleteToNextSubwordEnd,
DeleteToBeginningOfLine,
DeleteToEndOfLine,
- CutToEndOfLine,
+ DeleteToNextSubwordEnd,
+ DeleteToNextWordEnd,
+ DeleteToPreviousSubwordStart,
+ DeleteToPreviousWordStart,
DuplicateLine,
- MoveLineUp,
- MoveLineDown,
+ FindAllReferences,
+ Fold,
+ FoldSelectedRanges,
+ Format,
+ GoToDefinition,
+ GoToDefinitionSplit,
+ GoToDiagnostic,
+ GoToHunk,
+ GoToPrevDiagnostic,
+ GoToPrevHunk,
+ GoToTypeDefinition,
+ GoToTypeDefinitionSplit,
+ HalfPageDown,
+ HalfPageUp,
+ Hover,
+ Indent,
JoinLines,
- SortLinesCaseSensitive,
- SortLinesCaseInsensitive,
- ReverseLines,
- ShuffleLines,
- ConvertToUpperCase,
- ConvertToLowerCase,
- ConvertToTitleCase,
- ConvertToSnakeCase,
- ConvertToKebabCase,
- ConvertToUpperCamelCase,
- ConvertToLowerCamelCase,
- Transpose,
- Cut,
- Copy,
- Paste,
- Undo,
- Redo,
- MoveUp,
- PageUp,
+ LineDown,
+ LineUp,
MoveDown,
- PageDown,
MoveLeft,
+ MoveLineDown,
+ MoveLineUp,
MoveRight,
- MoveToPreviousWordStart,
- MoveToPreviousSubwordStart,
- MoveToNextWordEnd,
- MoveToNextSubwordEnd,
+ MoveToBeginning,
MoveToBeginningOfLine,
+ MoveToEnclosingBracket,
+ MoveToEnd,
MoveToEndOfLine,
- MoveToStartOfParagraph,
MoveToEndOfParagraph,
- MoveToBeginning,
- MoveToEnd,
- SelectUp,
+ MoveToNextSubwordEnd,
+ MoveToNextWordEnd,
+ MoveToPreviousSubwordStart,
+ MoveToPreviousWordStart,
+ MoveToStartOfParagraph,
+ MoveUp,
+ Newline,
+ NewlineAbove,
+ NewlineBelow,
+ NextScreen,
+ OpenExcerpts,
+ Outdent,
+ PageDown,
+ PageUp,
+ Paste,
+ Redo,
+ RedoSelection,
+ Rename,
+ RestartLanguageServer,
+ RevealInFinder,
+ ReverseLines,
+ ScrollCursorBottom,
+ ScrollCursorCenter,
+ ScrollCursorTop,
+ SelectAll,
SelectDown,
+ SelectLargerSyntaxNode,
SelectLeft,
+ SelectLine,
SelectRight,
- SelectToPreviousWordStart,
- SelectToPreviousSubwordStart,
- SelectToNextWordEnd,
- SelectToNextSubwordEnd,
- SelectToStartOfParagraph,
- SelectToEndOfParagraph,
+ SelectSmallerSyntaxNode,
SelectToBeginning,
SelectToEnd,
- SelectAll,
- SelectLine,
+ SelectToEndOfParagraph,
+ SelectToNextSubwordEnd,
+ SelectToNextWordEnd,
+ SelectToPreviousSubwordStart,
+ SelectToPreviousWordStart,
+ SelectToStartOfParagraph,
+ SelectUp,
+ ShowCharacterPalette,
+ ShowCompletions,
+ ShuffleLines,
+ SortLinesCaseInsensitive,
+ SortLinesCaseSensitive,
SplitSelectionIntoLines,
- AddSelectionAbove,
- AddSelectionBelow,
Tab,
TabPrev,
- ShowCharacterPalette,
- SelectLargerSyntaxNode,
- SelectSmallerSyntaxNode,
- GoToDefinition,
- GoToDefinitionSplit,
- GoToTypeDefinition,
- GoToTypeDefinitionSplit,
- MoveToEnclosingBracket,
+ ToggleInlayHints,
+ ToggleSoftWrap,
+ Transpose,
+ Undo,
UndoSelection,
- RedoSelection,
- FindAllReferences,
- Rename,
- ConfirmRename,
- Fold,
UnfoldLines,
- FoldSelectedRanges,
- ShowCompletions,
- OpenExcerpts,
- RestartLanguageServer,
- Hover,
- Format,
- ToggleSoftWrap,
- ToggleInlayHints,
- RevealInFinder,
- CopyPath,
- CopyRelativePath,
- CopyHighlightJson,
- ContextMenuFirst,
- ContextMenuPrev,
- ContextMenuNext,
- ContextMenuLast,
);
// impl_actions!(
@@ -532,7 +548,6 @@ pub fn init(cx: &mut AppContext) {
// cx.register_action_type(Editor::context_menu_last);
hover_popover::init(cx);
- scroll::actions::init(cx);
workspace::register_project_item::<Editor>(cx);
workspace::register_followable_item::<Editor>(cx);
@@ -988,7 +1003,7 @@ impl CompletionsMenu {
project: Option<Model<Project>>,
cx: &mut ViewContext<Editor>,
) {
- todo!("implementation below ");
+ // todo!("implementation below ");
}
// ) {
// let settings = EditorSettings::get_global(cx);
@@ -1155,7 +1170,7 @@ impl CompletionsMenu {
client: Arc<Client>,
language_registry: Arc<LanguageRegistry>,
) {
- todo!()
+ // todo!()
// let request = proto::ResolveCompletionDocumentation {
// project_id,
// language_server_id: server_id.0 as u64,
@@ -1199,7 +1214,7 @@ impl CompletionsMenu {
completion: lsp::CompletionItem,
language_registry: Arc<LanguageRegistry>,
) {
- todo!()
+ // todo!()
// let can_resolve = server
// .capabilities()
// .completion_provider
@@ -2383,45 +2398,45 @@ impl Editor {
.update(cx, |buffer, cx| buffer.edit(edits, None, cx));
}
- // pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
- // where
- // I: IntoIterator<Item = (Range<S>, T)>,
- // S: ToOffset,
- // T: Into<Arc<str>>,
- // {
- // if self.read_only {
- // return;
- // }
+ pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
+ where
+ I: IntoIterator<Item = (Range<S>, T)>,
+ S: ToOffset,
+ T: Into<Arc<str>>,
+ {
+ if self.read_only {
+ return;
+ }
- // self.buffer.update(cx, |buffer, cx| {
- // buffer.edit(edits, self.autoindent_mode.clone(), cx)
- // });
- // }
+ self.buffer.update(cx, |buffer, cx| {
+ buffer.edit(edits, self.autoindent_mode.clone(), cx)
+ });
+ }
- // pub fn edit_with_block_indent<I, S, T>(
- // &mut self,
- // edits: I,
- // original_indent_columns: Vec<u32>,
- // cx: &mut ViewContext<Self>,
- // ) where
- // I: IntoIterator<Item = (Range<S>, T)>,
- // S: ToOffset,
- // T: Into<Arc<str>>,
- // {
- // if self.read_only {
- // return;
- // }
+ pub fn edit_with_block_indent<I, S, T>(
+ &mut self,
+ edits: I,
+ original_indent_columns: Vec<u32>,
+ cx: &mut ViewContext<Self>,
+ ) where
+ I: IntoIterator<Item = (Range<S>, T)>,
+ S: ToOffset,
+ T: Into<Arc<str>>,
+ {
+ if self.read_only {
+ return;
+ }
- // self.buffer.update(cx, |buffer, cx| {
- // buffer.edit(
- // edits,
- // Some(AutoindentMode::Block {
- // original_indent_columns,
- // }),
- // cx,
- // )
- // });
- // }
+ self.buffer.update(cx, |buffer, cx| {
+ buffer.edit(
+ edits,
+ Some(AutoindentMode::Block {
+ original_indent_columns,
+ }),
+ cx,
+ )
+ });
+ }
fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
self.hide_context_menu(cx);
@@ -2734,40 +2749,40 @@ impl Editor {
self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
}
- // pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
- // if self.take_rename(false, cx).is_some() {
- // return;
- // }
+ pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
+ if self.take_rename(false, cx).is_some() {
+ return;
+ }
- // if hide_hover(self, cx) {
- // return;
- // }
+ if hide_hover(self, cx) {
+ return;
+ }
- // if self.hide_context_menu(cx).is_some() {
- // return;
- // }
+ if self.hide_context_menu(cx).is_some() {
+ return;
+ }
- // if self.discard_copilot_suggestion(cx) {
- // return;
- // }
+ if self.discard_copilot_suggestion(cx) {
+ return;
+ }
- // if self.snippet_stack.pop().is_some() {
- // return;
- // }
+ if self.snippet_stack.pop().is_some() {
+ return;
+ }
- // if self.mode == EditorMode::Full {
- // if self.active_diagnostics.is_some() {
- // self.dismiss_diagnostics(cx);
- // return;
- // }
+ if self.mode == EditorMode::Full {
+ if self.active_diagnostics.is_some() {
+ self.dismiss_diagnostics(cx);
+ return;
+ }
- // if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
- // return;
- // }
- // }
+ if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
+ return;
+ }
+ }
- // cx.propagate();
- // }
+ cx.propagate();
+ }
pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
let text: Arc<str> = text.into();
@@ -2961,263 +2976,263 @@ impl Editor {
});
}
- // pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
- // self.transact(cx, |this, cx| {
- // let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
- // let selections = this.selections.all::<usize>(cx);
- // let multi_buffer = this.buffer.read(cx);
- // let buffer = multi_buffer.snapshot(cx);
- // selections
- // .iter()
- // .map(|selection| {
- // let start_point = selection.start.to_point(&buffer);
- // let mut indent = buffer.indent_size_for_line(start_point.row);
- // indent.len = cmp::min(indent.len, start_point.column);
- // let start = selection.start;
- // let end = selection.end;
- // let is_cursor = start == end;
- // let language_scope = buffer.language_scope_at(start);
- // let (comment_delimiter, insert_extra_newline) = if let Some(language) =
- // &language_scope
- // {
- // let leading_whitespace_len = buffer
- // .reversed_chars_at(start)
- // .take_while(|c| c.is_whitespace() && *c != '\n')
- // .map(|c| c.len_utf8())
- // .sum::<usize>();
-
- // let trailing_whitespace_len = buffer
- // .chars_at(end)
- // .take_while(|c| c.is_whitespace() && *c != '\n')
- // .map(|c| c.len_utf8())
- // .sum::<usize>();
-
- // let insert_extra_newline =
- // language.brackets().any(|(pair, enabled)| {
- // let pair_start = pair.start.trim_end();
- // let pair_end = pair.end.trim_start();
-
- // enabled
- // && pair.newline
- // && buffer.contains_str_at(
- // end + trailing_whitespace_len,
- // pair_end,
- // )
- // && buffer.contains_str_at(
- // (start - leading_whitespace_len)
- // .saturating_sub(pair_start.len()),
- // pair_start,
- // )
- // });
- // // Comment extension on newline is allowed only for cursor selections
- // let comment_delimiter = language.line_comment_prefix().filter(|_| {
- // let is_comment_extension_enabled =
- // multi_buffer.settings_at(0, cx).extend_comment_on_newline;
- // is_cursor && is_comment_extension_enabled
- // });
- // let comment_delimiter = if let Some(delimiter) = comment_delimiter {
- // buffer
- // .buffer_line_for_row(start_point.row)
- // .is_some_and(|(snapshot, range)| {
- // let mut index_of_first_non_whitespace = 0;
- // let line_starts_with_comment = snapshot
- // .chars_for_range(range)
- // .skip_while(|c| {
- // let should_skip = c.is_whitespace();
- // if should_skip {
- // index_of_first_non_whitespace += 1;
- // }
- // should_skip
- // })
- // .take(delimiter.len())
- // .eq(delimiter.chars());
- // let cursor_is_placed_after_comment_marker =
- // index_of_first_non_whitespace + delimiter.len()
- // <= start_point.column as usize;
- // line_starts_with_comment
- // && cursor_is_placed_after_comment_marker
- // })
- // .then(|| delimiter.clone())
- // } else {
- // None
- // };
- // (comment_delimiter, insert_extra_newline)
- // } else {
- // (None, false)
- // };
-
- // let capacity_for_delimiter = comment_delimiter
- // .as_deref()
- // .map(str::len)
- // .unwrap_or_default();
- // let mut new_text =
- // String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
- // new_text.push_str("\n");
- // new_text.extend(indent.chars());
- // if let Some(delimiter) = &comment_delimiter {
- // new_text.push_str(&delimiter);
- // }
- // if insert_extra_newline {
- // new_text = new_text.repeat(2);
- // }
-
- // let anchor = buffer.anchor_after(end);
- // let new_selection = selection.map(|_| anchor);
- // (
- // (start..end, new_text),
- // (insert_extra_newline, new_selection),
- // )
- // })
- // .unzip()
- // };
+ pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
+ self.transact(cx, |this, cx| {
+ let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
+ let selections = this.selections.all::<usize>(cx);
+ let multi_buffer = this.buffer.read(cx);
+ let buffer = multi_buffer.snapshot(cx);
+ selections
+ .iter()
+ .map(|selection| {
+ let start_point = selection.start.to_point(&buffer);
+ let mut indent = buffer.indent_size_for_line(start_point.row);
+ indent.len = cmp::min(indent.len, start_point.column);
+ let start = selection.start;
+ let end = selection.end;
+ let is_cursor = start == end;
+ let language_scope = buffer.language_scope_at(start);
+ let (comment_delimiter, insert_extra_newline) = if let Some(language) =
+ &language_scope
+ {
+ let leading_whitespace_len = buffer
+ .reversed_chars_at(start)
+ .take_while(|c| c.is_whitespace() && *c != '\n')
+ .map(|c| c.len_utf8())
+ .sum::<usize>();
+
+ let trailing_whitespace_len = buffer
+ .chars_at(end)
+ .take_while(|c| c.is_whitespace() && *c != '\n')
+ .map(|c| c.len_utf8())
+ .sum::<usize>();
+
+ let insert_extra_newline =
+ language.brackets().any(|(pair, enabled)| {
+ let pair_start = pair.start.trim_end();
+ let pair_end = pair.end.trim_start();
+
+ enabled
+ && pair.newline
+ && buffer.contains_str_at(
+ end + trailing_whitespace_len,
+ pair_end,
+ )
+ && buffer.contains_str_at(
+ (start - leading_whitespace_len)
+ .saturating_sub(pair_start.len()),
+ pair_start,
+ )
+ });
+ // Comment extension on newline is allowed only for cursor selections
+ let comment_delimiter = language.line_comment_prefix().filter(|_| {
+ let is_comment_extension_enabled =
+ multi_buffer.settings_at(0, cx).extend_comment_on_newline;
+ is_cursor && is_comment_extension_enabled
+ });
+ let comment_delimiter = if let Some(delimiter) = comment_delimiter {
+ buffer
+ .buffer_line_for_row(start_point.row)
+ .is_some_and(|(snapshot, range)| {
+ let mut index_of_first_non_whitespace = 0;
+ let line_starts_with_comment = snapshot
+ .chars_for_range(range)
+ .skip_while(|c| {
+ let should_skip = c.is_whitespace();
+ if should_skip {
+ index_of_first_non_whitespace += 1;
+ }
+ should_skip
+ })
+ .take(delimiter.len())
+ .eq(delimiter.chars());
+ let cursor_is_placed_after_comment_marker =
+ index_of_first_non_whitespace + delimiter.len()
+ <= start_point.column as usize;
+ line_starts_with_comment
+ && cursor_is_placed_after_comment_marker
+ })
+ .then(|| delimiter.clone())
+ } else {
+ None
+ };
+ (comment_delimiter, insert_extra_newline)
+ } else {
+ (None, false)
+ };
+
+ let capacity_for_delimiter = comment_delimiter
+ .as_deref()
+ .map(str::len)
+ .unwrap_or_default();
+ let mut new_text =
+ String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
+ new_text.push_str("\n");
+ new_text.extend(indent.chars());
+ if let Some(delimiter) = &comment_delimiter {
+ new_text.push_str(&delimiter);
+ }
+ if insert_extra_newline {
+ new_text = new_text.repeat(2);
+ }
- // this.edit_with_autoindent(edits, cx);
- // let buffer = this.buffer.read(cx).snapshot(cx);
- // let new_selections = selection_fixup_info
- // .into_iter()
- // .map(|(extra_newline_inserted, new_selection)| {
- // let mut cursor = new_selection.end.to_point(&buffer);
- // if extra_newline_inserted {
- // cursor.row -= 1;
- // cursor.column = buffer.line_len(cursor.row);
- // }
- // new_selection.map(|_| cursor)
- // })
- // .collect();
+ let anchor = buffer.anchor_after(end);
+ let new_selection = selection.map(|_| anchor);
+ (
+ (start..end, new_text),
+ (insert_extra_newline, new_selection),
+ )
+ })
+ .unzip()
+ };
- // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
- // this.refresh_copilot_suggestions(true, cx);
- // });
- // }
+ this.edit_with_autoindent(edits, cx);
+ let buffer = this.buffer.read(cx).snapshot(cx);
+ let new_selections = selection_fixup_info
+ .into_iter()
+ .map(|(extra_newline_inserted, new_selection)| {
+ let mut cursor = new_selection.end.to_point(&buffer);
+ if extra_newline_inserted {
+ cursor.row -= 1;
+ cursor.column = buffer.line_len(cursor.row);
+ }
+ new_selection.map(|_| cursor)
+ })
+ .collect();
- // pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
- // let buffer = self.buffer.read(cx);
- // let snapshot = buffer.snapshot(cx);
+ this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
+ this.refresh_copilot_suggestions(true, cx);
+ });
+ }
- // let mut edits = Vec::new();
- // let mut rows = Vec::new();
- // let mut rows_inserted = 0;
+ pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
+ let buffer = self.buffer.read(cx);
+ let snapshot = buffer.snapshot(cx);
- // for selection in self.selections.all_adjusted(cx) {
- // let cursor = selection.head();
- // let row = cursor.row;
+ let mut edits = Vec::new();
+ let mut rows = Vec::new();
+ let mut rows_inserted = 0;
- // let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
+ for selection in self.selections.all_adjusted(cx) {
+ let cursor = selection.head();
+ let row = cursor.row;
- // let newline = "\n".to_string();
- // edits.push((start_of_line..start_of_line, newline));
+ let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
- // rows.push(row + rows_inserted);
- // rows_inserted += 1;
- // }
+ let newline = "\n".to_string();
+ edits.push((start_of_line..start_of_line, newline));
- // self.transact(cx, |editor, cx| {
- // editor.edit(edits, cx);
+ rows.push(row + rows_inserted);
+ rows_inserted += 1;
+ }
- // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
- // let mut index = 0;
- // s.move_cursors_with(|map, _, _| {
- // let row = rows[index];
- // index += 1;
+ self.transact(cx, |editor, cx| {
+ editor.edit(edits, cx);
- // let point = Point::new(row, 0);
- // let boundary = map.next_line_boundary(point).1;
- // let clipped = map.clip_point(boundary, Bias::Left);
+ editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+ let mut index = 0;
+ s.move_cursors_with(|map, _, _| {
+ let row = rows[index];
+ index += 1;
- // (clipped, SelectionGoal::None)
- // });
- // });
+ let point = Point::new(row, 0);
+ let boundary = map.next_line_boundary(point).1;
+ let clipped = map.clip_point(boundary, Bias::Left);
- // let mut indent_edits = Vec::new();
- // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
- // for row in rows {
- // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
- // for (row, indent) in indents {
- // if indent.len == 0 {
- // continue;
- // }
+ (clipped, SelectionGoal::None)
+ });
+ });
- // let text = match indent.kind {
- // IndentKind::Space => " ".repeat(indent.len as usize),
- // IndentKind::Tab => "\t".repeat(indent.len as usize),
- // };
- // let point = Point::new(row, 0);
- // indent_edits.push((point..point, text));
- // }
- // }
- // editor.edit(indent_edits, cx);
- // });
- // }
+ let mut indent_edits = Vec::new();
+ let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
+ for row in rows {
+ let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
+ for (row, indent) in indents {
+ if indent.len == 0 {
+ continue;
+ }
- // pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
- // let buffer = self.buffer.read(cx);
- // let snapshot = buffer.snapshot(cx);
+ let text = match indent.kind {
+ IndentKind::Space => " ".repeat(indent.len as usize),
+ IndentKind::Tab => "\t".repeat(indent.len as usize),
+ };
+ let point = Point::new(row, 0);
+ indent_edits.push((point..point, text));
+ }
+ }
+ editor.edit(indent_edits, cx);
+ });
+ }
- // let mut edits = Vec::new();
- // let mut rows = Vec::new();
- // let mut rows_inserted = 0;
+ pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
+ let buffer = self.buffer.read(cx);
+ let snapshot = buffer.snapshot(cx);
- // for selection in self.selections.all_adjusted(cx) {
- // let cursor = selection.head();
- // let row = cursor.row;
+ let mut edits = Vec::new();
+ let mut rows = Vec::new();
+ let mut rows_inserted = 0;
- // let point = Point::new(row + 1, 0);
- // let start_of_line = snapshot.clip_point(point, Bias::Left);
+ for selection in self.selections.all_adjusted(cx) {
+ let cursor = selection.head();
+ let row = cursor.row;
- // let newline = "\n".to_string();
- // edits.push((start_of_line..start_of_line, newline));
+ let point = Point::new(row + 1, 0);
+ let start_of_line = snapshot.clip_point(point, Bias::Left);
- // rows_inserted += 1;
- // rows.push(row + rows_inserted);
- // }
+ let newline = "\n".to_string();
+ edits.push((start_of_line..start_of_line, newline));
- // self.transact(cx, |editor, cx| {
- // editor.edit(edits, cx);
+ rows_inserted += 1;
+ rows.push(row + rows_inserted);
+ }
- // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
- // let mut index = 0;
- // s.move_cursors_with(|map, _, _| {
- // let row = rows[index];
- // index += 1;
+ self.transact(cx, |editor, cx| {
+ editor.edit(edits, cx);
- // let point = Point::new(row, 0);
- // let boundary = map.next_line_boundary(point).1;
- // let clipped = map.clip_point(boundary, Bias::Left);
+ editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+ let mut index = 0;
+ s.move_cursors_with(|map, _, _| {
+ let row = rows[index];
+ index += 1;
- // (clipped, SelectionGoal::None)
- // });
- // });
+ let point = Point::new(row, 0);
+ let boundary = map.next_line_boundary(point).1;
+ let clipped = map.clip_point(boundary, Bias::Left);
- // let mut indent_edits = Vec::new();
- // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
- // for row in rows {
- // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
- // for (row, indent) in indents {
- // if indent.len == 0 {
- // continue;
- // }
+ (clipped, SelectionGoal::None)
+ });
+ });
- // let text = match indent.kind {
- // IndentKind::Space => " ".repeat(indent.len as usize),
- // IndentKind::Tab => "\t".repeat(indent.len as usize),
- // };
- // let point = Point::new(row, 0);
- // indent_edits.push((point..point, text));
- // }
- // }
- // editor.edit(indent_edits, cx);
- // });
- // }
+ let mut indent_edits = Vec::new();
+ let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
+ for row in rows {
+ let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
+ for (row, indent) in indents {
+ if indent.len == 0 {
+ continue;
+ }
- // pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
- // self.insert_with_autoindent_mode(
- // text,
- // Some(AutoindentMode::Block {
- // original_indent_columns: Vec::new(),
- // }),
- // cx,
- // );
- // }
+ let text = match indent.kind {
+ IndentKind::Space => " ".repeat(indent.len as usize),
+ IndentKind::Tab => "\t".repeat(indent.len as usize),
+ };
+ let point = Point::new(row, 0);
+ indent_edits.push((point..point, text));
+ }
+ }
+ editor.edit(indent_edits, cx);
+ });
+ }
+
+ pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
+ self.insert_with_autoindent_mode(
+ text,
+ Some(AutoindentMode::Block {
+ original_indent_columns: Vec::new(),
+ }),
+ cx,
+ );
+ }
fn insert_with_autoindent_mode(
&mut self,
@@ -2,8 +2,10 @@ use crate::{
display_map::{BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint},
editor_settings::ShowScrollbar,
git::{diff_hunk_to_display, DisplayDiffHunk},
+ scroll::scroll_amount::ScrollAmount,
CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
- MoveDown, Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN,
+ HalfPageDown, HalfPageUp, LineDown, LineUp, MoveDown, PageDown, PageUp, Point, Selection,
+ SoftWrap, ToPoint, MAX_LINE_LEN,
};
use anyhow::Result;
use collections::{BTreeMap, HashMap};
@@ -31,6 +33,7 @@ use std::{
};
use sum_tree::Bias;
use theme::{ActiveTheme, PlayerColor};
+use util::ResultExt;
use workspace::item::Item;
enum FoldMarkers {}
@@ -2562,6 +2565,153 @@ impl Element<Editor> for EditorElement {
build_action_listener(Editor::move_right),
build_action_listener(Editor::move_down),
build_action_listener(Editor::move_up),
+ // build_action_listener(Editor::new_file), todo!()
+ // build_action_listener(Editor::new_file_in_direction), todo!()
+ build_action_listener(Editor::cancel),
+ build_action_listener(Editor::newline),
+ build_action_listener(Editor::newline_above),
+ build_action_listener(Editor::newline_below),
+ build_action_listener(Editor::backspace),
+ build_action_listener(Editor::delete),
+ build_action_listener(Editor::tab),
+ build_action_listener(Editor::tab_prev),
+ build_action_listener(Editor::indent),
+ build_action_listener(Editor::outdent),
+ build_action_listener(Editor::delete_line),
+ build_action_listener(Editor::join_lines),
+ build_action_listener(Editor::sort_lines_case_sensitive),
+ build_action_listener(Editor::sort_lines_case_insensitive),
+ build_action_listener(Editor::reverse_lines),
+ build_action_listener(Editor::shuffle_lines),
+ build_action_listener(Editor::convert_to_upper_case),
+ build_action_listener(Editor::convert_to_lower_case),
+ build_action_listener(Editor::convert_to_title_case),
+ build_action_listener(Editor::convert_to_snake_case),
+ build_action_listener(Editor::convert_to_kebab_case),
+ build_action_listener(Editor::convert_to_upper_camel_case),
+ build_action_listener(Editor::convert_to_lower_camel_case),
+ build_action_listener(Editor::delete_to_previous_word_start),
+ build_action_listener(Editor::delete_to_previous_subword_start),
+ build_action_listener(Editor::delete_to_next_word_end),
+ build_action_listener(Editor::delete_to_next_subword_end),
+ build_action_listener(Editor::delete_to_beginning_of_line),
+ build_action_listener(Editor::delete_to_end_of_line),
+ build_action_listener(Editor::cut_to_end_of_line),
+ build_action_listener(Editor::duplicate_line),
+ build_action_listener(Editor::move_line_up),
+ build_action_listener(Editor::move_line_down),
+ build_action_listener(Editor::transpose),
+ build_action_listener(Editor::cut),
+ build_action_listener(Editor::copy),
+ build_action_listener(Editor::paste),
+ build_action_listener(Editor::undo),
+ build_action_listener(Editor::redo),
+ build_action_listener(Editor::move_page_up),
+ build_action_listener(Editor::move_page_down),
+ build_action_listener(Editor::next_screen),
+ build_action_listener(Editor::scroll_cursor_top),
+ build_action_listener(Editor::scroll_cursor_center),
+ build_action_listener(Editor::scroll_cursor_bottom),
+ build_action_listener(|editor, _: &LineDown, cx| {
+ editor.scroll_screen(&ScrollAmount::Line(1.), cx)
+ }),
+ build_action_listener(|editor, _: &LineUp, cx| {
+ editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
+ }),
+ build_action_listener(|editor, _: &HalfPageDown, cx| {
+ editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
+ }),
+ build_action_listener(|editor, _: &HalfPageUp, cx| {
+ editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
+ }),
+ build_action_listener(|editor, _: &PageDown, cx| {
+ editor.scroll_screen(&ScrollAmount::Page(1.), cx)
+ }),
+ build_action_listener(|editor, _: &PageUp, cx| {
+ editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
+ }),
+ build_action_listener(Editor::move_to_previous_word_start),
+ build_action_listener(Editor::move_to_previous_subword_start),
+ build_action_listener(Editor::move_to_next_word_end),
+ build_action_listener(Editor::move_to_next_subword_end),
+ build_action_listener(Editor::move_to_beginning_of_line),
+ build_action_listener(Editor::move_to_end_of_line),
+ build_action_listener(Editor::move_to_start_of_paragraph),
+ build_action_listener(Editor::move_to_end_of_paragraph),
+ build_action_listener(Editor::move_to_beginning),
+ build_action_listener(Editor::move_to_end),
+ build_action_listener(Editor::select_up),
+ build_action_listener(Editor::select_down),
+ build_action_listener(Editor::select_left),
+ build_action_listener(Editor::select_right),
+ build_action_listener(Editor::select_to_previous_word_start),
+ build_action_listener(Editor::select_to_previous_subword_start),
+ build_action_listener(Editor::select_to_next_word_end),
+ build_action_listener(Editor::select_to_next_subword_end),
+ build_action_listener(Editor::select_to_beginning_of_line),
+ build_action_listener(Editor::select_to_end_of_line),
+ build_action_listener(Editor::select_to_start_of_paragraph),
+ build_action_listener(Editor::select_to_end_of_paragraph),
+ build_action_listener(Editor::select_to_beginning),
+ build_action_listener(Editor::select_to_end),
+ build_action_listener(Editor::select_all),
+ build_action_listener(|editor, action, cx| {
+ editor.select_all_matches(action, cx).log_err();
+ }),
+ build_action_listener(Editor::select_line),
+ build_action_listener(Editor::split_selection_into_lines),
+ build_action_listener(Editor::add_selection_above),
+ build_action_listener(Editor::add_selection_below),
+ build_action_listener(|editor, action, cx| {
+ editor.select_next(action, cx).log_err();
+ }),
+ build_action_listener(|editor, action, cx| {
+ editor.select_previous(action, cx).log_err();
+ }),
+ build_action_listener(Editor::toggle_comments),
+ build_action_listener(Editor::select_larger_syntax_node),
+ build_action_listener(Editor::select_smaller_syntax_node),
+ build_action_listener(Editor::move_to_enclosing_bracket),
+ build_action_listener(Editor::undo_selection),
+ build_action_listener(Editor::redo_selection),
+ build_action_listener(Editor::go_to_diagnostic),
+ build_action_listener(Editor::go_to_prev_diagnostic),
+ build_action_listener(Editor::go_to_hunk),
+ build_action_listener(Editor::go_to_prev_hunk),
+ build_action_listener(Editor::go_to_definition),
+ build_action_listener(Editor::go_to_definition_split),
+ build_action_listener(Editor::go_to_type_definition),
+ build_action_listener(Editor::go_to_type_definition_split),
+ build_action_listener(Editor::fold),
+ build_action_listener(Editor::fold_at),
+ build_action_listener(Editor::unfold_lines),
+ build_action_listener(Editor::unfold_at),
+ // build_action_listener(Editor::gutter_hover), todo!()
+ build_action_listener(Editor::fold_selected_ranges),
+ build_action_listener(Editor::show_completions),
+ // build_action_listener(Editor::toggle_code_actions), todo!()
+ // build_action_listener(Editor::open_excerpts), todo!()
+ build_action_listener(Editor::toggle_soft_wrap),
+ build_action_listener(Editor::toggle_inlay_hints),
+ build_action_listener(Editor::reveal_in_finder),
+ build_action_listener(Editor::copy_path),
+ build_action_listener(Editor::copy_relative_path),
+ build_action_listener(Editor::copy_highlight_json),
+ build_action_listener(|editor, action, cx| {
+ editor
+ .format(action, cx)
+ .map(|task| task.detach_and_log_err(cx));
+ }),
+ build_action_listener(Editor::restart_language_server),
+ build_action_listener(Editor::show_character_palette),
+ // build_action_listener(Editor::confirm_completion), todo!()
+ // build_action_listener(Editor::confirm_code_action), todo!()
+ // build_action_listener(Editor::rename), todo!()
+ // build_action_listener(Editor::confirm_rename), todo!()
+ // build_action_listener(Editor::find_all_references), todo!()
+ build_action_listener(Editor::next_copilot_suggestion),
+ build_action_listener(Editor::previous_copilot_suggestion),
+ build_action_listener(Editor::copilot_suggest),
build_key_listener(
move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
if phase == DispatchPhase::Bubble {