Merge branch 'main' into storybook
This commit is contained in:
+45
-31
@@ -312,6 +312,10 @@ actions!(
|
||||
CopyPath,
|
||||
CopyRelativePath,
|
||||
CopyHighlightJson,
|
||||
ContextMenuFirst,
|
||||
ContextMenuPrev,
|
||||
ContextMenuNext,
|
||||
ContextMenuLast,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -468,6 +472,10 @@ pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(Editor::next_copilot_suggestion);
|
||||
cx.add_action(Editor::previous_copilot_suggestion);
|
||||
cx.add_action(Editor::copilot_suggest);
|
||||
cx.add_action(Editor::context_menu_first);
|
||||
cx.add_action(Editor::context_menu_prev);
|
||||
cx.add_action(Editor::context_menu_next);
|
||||
cx.add_action(Editor::context_menu_last);
|
||||
|
||||
hover_popover::init(cx);
|
||||
scroll::actions::init(cx);
|
||||
@@ -1654,7 +1662,7 @@ impl Editor {
|
||||
.excerpt_containing(self.selections.newest_anchor().head(), cx)
|
||||
}
|
||||
|
||||
fn style(&self, cx: &AppContext) -> EditorStyle {
|
||||
pub fn style(&self, cx: &AppContext) -> EditorStyle {
|
||||
build_style(
|
||||
settings::get::<ThemeSettings>(cx),
|
||||
self.get_field_editor_theme.as_deref(),
|
||||
@@ -5166,12 +5174,6 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
if context_menu.select_prev(cx) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(self.mode, EditorMode::SingleLine) {
|
||||
cx.propagate_action();
|
||||
return;
|
||||
@@ -5194,15 +5196,6 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if self
|
||||
.context_menu
|
||||
.as_mut()
|
||||
.map(|menu| menu.select_first(cx))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(self.mode, EditorMode::SingleLine) {
|
||||
cx.propagate_action();
|
||||
return;
|
||||
@@ -5242,12 +5235,6 @@ impl Editor {
|
||||
pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
|
||||
self.take_rename(true, cx);
|
||||
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
if context_menu.select_next(cx) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if self.mode == EditorMode::SingleLine {
|
||||
cx.propagate_action();
|
||||
return;
|
||||
@@ -5315,6 +5302,30 @@ impl Editor {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
context_menu.select_first(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
context_menu.select_prev(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
context_menu.select_next(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
|
||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||
context_menu.select_last(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_to_previous_word_start(
|
||||
&mut self,
|
||||
_: &MoveToPreviousWordStart,
|
||||
@@ -8666,17 +8677,20 @@ impl View for Editor {
|
||||
if self.pending_rename.is_some() {
|
||||
keymap.add_identifier("renaming");
|
||||
}
|
||||
match self.context_menu.as_ref() {
|
||||
Some(ContextMenu::Completions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_completions")
|
||||
if self.context_menu_visible() {
|
||||
match self.context_menu.as_ref() {
|
||||
Some(ContextMenu::Completions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_completions")
|
||||
}
|
||||
Some(ContextMenu::CodeActions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_code_actions")
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
Some(ContextMenu::CodeActions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_code_actions")
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
for layer in self.keymap_context_layers.values() {
|
||||
keymap.extend(layer);
|
||||
}
|
||||
|
||||
@@ -5340,7 +5340,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor.move_down(&MoveDown, cx);
|
||||
editor.context_menu_next(&Default::default(), cx);
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap()
|
||||
|
||||
+62
-115
@@ -1,8 +1,14 @@
|
||||
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
||||
use crate::{char_kind, CharKind, ToPoint};
|
||||
use crate::{char_kind, CharKind, ToOffset, ToPoint};
|
||||
use language::Point;
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum FindRange {
|
||||
SingleLine,
|
||||
MultiLine,
|
||||
}
|
||||
|
||||
pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {
|
||||
if point.column() > 0 {
|
||||
*point.column_mut() -= 1;
|
||||
@@ -179,7 +185,7 @@ pub fn previous_word_start(map: &DisplaySnapshot, point: DisplayPoint) -> Displa
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
|
||||
find_preceding_boundary(map, point, |left, right| {
|
||||
find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
(char_kind(&scope, left) != char_kind(&scope, right) && !right.is_whitespace())
|
||||
|| left == '\n'
|
||||
})
|
||||
@@ -188,7 +194,8 @@ pub fn previous_word_start(map: &DisplaySnapshot, point: DisplayPoint) -> Displa
|
||||
pub fn previous_subword_start(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
find_preceding_boundary(map, point, |left, right| {
|
||||
|
||||
find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let is_word_start =
|
||||
char_kind(&scope, left) != char_kind(&scope, right) && !right.is_whitespace();
|
||||
let is_subword_start =
|
||||
@@ -200,7 +207,8 @@ pub fn previous_subword_start(map: &DisplaySnapshot, point: DisplayPoint) -> Dis
|
||||
pub fn next_word_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
find_boundary(map, point, |left, right| {
|
||||
|
||||
find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
(char_kind(&scope, left) != char_kind(&scope, right) && !left.is_whitespace())
|
||||
|| right == '\n'
|
||||
})
|
||||
@@ -209,7 +217,8 @@ pub fn next_word_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint
|
||||
pub fn next_subword_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
find_boundary(map, point, |left, right| {
|
||||
|
||||
find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let is_word_end =
|
||||
(char_kind(&scope, left) != char_kind(&scope, right)) && !left.is_whitespace();
|
||||
let is_subword_end =
|
||||
@@ -272,79 +281,34 @@ pub fn end_of_paragraph(
|
||||
map.max_point()
|
||||
}
|
||||
|
||||
/// Scans for a boundary preceding the given start point `from` until a boundary is found, indicated by the
|
||||
/// given predicate returning true. The predicate is called with the character to the left and right
|
||||
/// of the candidate boundary location, and will be called with `\n` characters indicating the start
|
||||
/// or end of a line.
|
||||
/// Scans for a boundary preceding the given start point `from` until a boundary is found,
|
||||
/// indicated by the given predicate returning true.
|
||||
/// The predicate is called with the character to the left and right of the candidate boundary location.
|
||||
/// If FindRange::SingleLine is specified and no boundary is found before the start of the current line, the start of the current line will be returned.
|
||||
pub fn find_preceding_boundary(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
find_range: FindRange,
|
||||
mut is_boundary: impl FnMut(char, char) -> bool,
|
||||
) -> DisplayPoint {
|
||||
let mut start_column = 0;
|
||||
let mut soft_wrap_row = from.row() + 1;
|
||||
let mut prev_ch = None;
|
||||
let mut offset = from.to_point(map).to_offset(&map.buffer_snapshot);
|
||||
|
||||
let mut prev = None;
|
||||
for (ch, point) in map.reverse_chars_at(from) {
|
||||
// Recompute soft_wrap_indent if the row has changed
|
||||
if point.row() != soft_wrap_row {
|
||||
soft_wrap_row = point.row();
|
||||
|
||||
if point.row() == 0 {
|
||||
start_column = 0;
|
||||
} else if let Some(indent) = map.soft_wrap_indent(point.row() - 1) {
|
||||
start_column = indent;
|
||||
}
|
||||
}
|
||||
|
||||
// If the current point is in the soft_wrap, skip comparing it
|
||||
if point.column() < start_column {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((prev_ch, prev_point)) = prev {
|
||||
if is_boundary(ch, prev_ch) {
|
||||
return map.clip_point(prev_point, Bias::Left);
|
||||
}
|
||||
}
|
||||
|
||||
prev = Some((ch, point));
|
||||
}
|
||||
map.clip_point(DisplayPoint::zero(), Bias::Left)
|
||||
}
|
||||
|
||||
/// Scans for a boundary preceding the given start point `from` until a boundary is found, indicated by the
|
||||
/// given predicate returning true. The predicate is called with the character to the left and right
|
||||
/// of the candidate boundary location, and will be called with `\n` characters indicating the start
|
||||
/// or end of a line. If no boundary is found, the start of the line is returned.
|
||||
pub fn find_preceding_boundary_in_line(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
mut is_boundary: impl FnMut(char, char) -> bool,
|
||||
) -> DisplayPoint {
|
||||
let mut start_column = 0;
|
||||
if from.row() > 0 {
|
||||
if let Some(indent) = map.soft_wrap_indent(from.row() - 1) {
|
||||
start_column = indent;
|
||||
}
|
||||
}
|
||||
|
||||
let mut prev = None;
|
||||
for (ch, point) in map.reverse_chars_at(from) {
|
||||
if let Some((prev_ch, prev_point)) = prev {
|
||||
if is_boundary(ch, prev_ch) {
|
||||
return map.clip_point(prev_point, Bias::Left);
|
||||
}
|
||||
}
|
||||
|
||||
if ch == '\n' || point.column() < start_column {
|
||||
for ch in map.buffer_snapshot.reversed_chars_at(offset) {
|
||||
if find_range == FindRange::SingleLine && ch == '\n' {
|
||||
break;
|
||||
}
|
||||
if let Some(prev_ch) = prev_ch {
|
||||
if is_boundary(ch, prev_ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
prev = Some((ch, point));
|
||||
offset -= ch.len_utf8();
|
||||
prev_ch = Some(ch);
|
||||
}
|
||||
|
||||
map.clip_point(prev.map(|(_, point)| point).unwrap_or(from), Bias::Left)
|
||||
map.clip_point(offset.to_display_point(map), Bias::Left)
|
||||
}
|
||||
|
||||
/// Scans for a boundary following the given start point until a boundary is found, indicated by the
|
||||
@@ -354,47 +318,26 @@ pub fn find_preceding_boundary_in_line(
|
||||
pub fn find_boundary(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
find_range: FindRange,
|
||||
mut is_boundary: impl FnMut(char, char) -> bool,
|
||||
) -> DisplayPoint {
|
||||
let mut offset = from.to_offset(&map, Bias::Right);
|
||||
let mut prev_ch = None;
|
||||
for (ch, point) in map.chars_at(from) {
|
||||
if let Some(prev_ch) = prev_ch {
|
||||
if is_boundary(prev_ch, ch) {
|
||||
return map.clip_point(point, Bias::Right);
|
||||
}
|
||||
}
|
||||
|
||||
prev_ch = Some(ch);
|
||||
}
|
||||
map.clip_point(map.max_point(), Bias::Right)
|
||||
}
|
||||
|
||||
/// Scans for a boundary following the given start point until a boundary is found, indicated by the
|
||||
/// given predicate returning true. The predicate is called with the character to the left and right
|
||||
/// of the candidate boundary location, and will be called with `\n` characters indicating the start
|
||||
/// or end of a line. If no boundary is found, the end of the line is returned
|
||||
pub fn find_boundary_in_line(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
mut is_boundary: impl FnMut(char, char) -> bool,
|
||||
) -> DisplayPoint {
|
||||
let mut prev = None;
|
||||
for (ch, point) in map.chars_at(from) {
|
||||
if let Some((prev_ch, _)) = prev {
|
||||
if is_boundary(prev_ch, ch) {
|
||||
return map.clip_point(point, Bias::Right);
|
||||
}
|
||||
}
|
||||
|
||||
prev = Some((ch, point));
|
||||
|
||||
if ch == '\n' {
|
||||
for ch in map.buffer_snapshot.chars_at(offset) {
|
||||
if find_range == FindRange::SingleLine && ch == '\n' {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(prev_ch) = prev_ch {
|
||||
if is_boundary(prev_ch, ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last position checked so that we give a point right before the newline or eof.
|
||||
map.clip_point(prev.map(|(_, point)| point).unwrap_or(from), Bias::Right)
|
||||
offset += ch.len_utf8();
|
||||
prev_ch = Some(ch);
|
||||
}
|
||||
map.clip_point(offset.to_display_point(map), Bias::Right)
|
||||
}
|
||||
|
||||
pub fn is_inside_word(map: &DisplaySnapshot, point: DisplayPoint) -> bool {
|
||||
@@ -533,7 +476,12 @@ mod tests {
|
||||
) {
|
||||
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
|
||||
assert_eq!(
|
||||
find_preceding_boundary(&snapshot, display_points[1], is_boundary),
|
||||
find_preceding_boundary(
|
||||
&snapshot,
|
||||
display_points[1],
|
||||
FindRange::MultiLine,
|
||||
is_boundary
|
||||
),
|
||||
display_points[0]
|
||||
);
|
||||
}
|
||||
@@ -612,21 +560,15 @@ mod tests {
|
||||
find_preceding_boundary(
|
||||
&snapshot,
|
||||
buffer_snapshot.len().to_display_point(&snapshot),
|
||||
|left, _| left == 'a',
|
||||
FindRange::MultiLine,
|
||||
|left, _| left == 'e',
|
||||
),
|
||||
0.to_display_point(&snapshot),
|
||||
snapshot
|
||||
.buffer_snapshot
|
||||
.offset_to_point(5)
|
||||
.to_display_point(&snapshot),
|
||||
"Should not stop at inlays when looking for boundaries"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
find_preceding_boundary_in_line(
|
||||
&snapshot,
|
||||
buffer_snapshot.len().to_display_point(&snapshot),
|
||||
|left, _| left == 'a',
|
||||
),
|
||||
0.to_display_point(&snapshot),
|
||||
"Should not stop at inlays when looking for boundaries in line"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
@@ -699,7 +641,12 @@ mod tests {
|
||||
) {
|
||||
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
|
||||
assert_eq!(
|
||||
find_boundary(&snapshot, display_points[0], is_boundary),
|
||||
find_boundary(
|
||||
&snapshot,
|
||||
display_points[0],
|
||||
FindRange::MultiLine,
|
||||
is_boundary
|
||||
),
|
||||
display_points[1]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -378,10 +378,6 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if amount.move_context_menu_selection(self, cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cur_position = self.scroll_position(cx);
|
||||
let new_pos = cur_position + vec2f(0., amount.lines(self));
|
||||
self.set_scroll_position(new_pos, cx);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use gpui::ViewContext;
|
||||
use serde::Deserialize;
|
||||
use util::iife;
|
||||
|
||||
use crate::Editor;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize)]
|
||||
pub enum ScrollAmount {
|
||||
@@ -13,25 +10,6 @@ pub enum ScrollAmount {
|
||||
}
|
||||
|
||||
impl ScrollAmount {
|
||||
pub fn move_context_menu_selection(
|
||||
&self,
|
||||
editor: &mut Editor,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
iife!({
|
||||
let context_menu = editor.context_menu.as_mut()?;
|
||||
|
||||
match self {
|
||||
Self::Line(c) if *c > 0. => context_menu.select_next(cx),
|
||||
Self::Line(_) => context_menu.select_prev(cx),
|
||||
Self::Page(c) if *c > 0. => context_menu.select_last(cx),
|
||||
Self::Page(_) => context_menu.select_first(cx),
|
||||
}
|
||||
.then_some(())
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn lines(&self, editor: &mut Editor) -> f32 {
|
||||
match self {
|
||||
Self::Line(count) => *count,
|
||||
@@ -39,7 +17,7 @@ impl ScrollAmount {
|
||||
.visible_line_count()
|
||||
// subtract one to leave an anchor line
|
||||
// round towards zero (so page-up and page-down are symmetric)
|
||||
.map(|l| ((l - 1.) * count).trunc())
|
||||
.map(|l| (l * count).trunc() - count.signum())
|
||||
.unwrap_or(0.),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user