Merge branch 'main' into multi-server-completions-tailwind

This commit is contained in:
Julia 2023-08-30 22:41:12 -04:00
commit ff3865a4ad
427 changed files with 43123 additions and 12861 deletions

View file

@ -1,8 +1,8 @@
use std::sync::Arc;
use std::{cmp, sync::Arc};
use editor::{
char_kind,
display_map::{DisplaySnapshot, ToDisplayPoint},
display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint},
movement, Bias, CharKind, DisplayPoint, ToOffset,
};
use gpui::{actions, impl_actions, AppContext, WindowContext};
@ -21,16 +21,16 @@ use crate::{
pub enum Motion {
Left,
Backspace,
Down,
Up,
Down { display_lines: bool },
Up { display_lines: bool },
Right,
NextWordStart { ignore_punctuation: bool },
NextWordEnd { ignore_punctuation: bool },
PreviousWordStart { ignore_punctuation: bool },
FirstNonWhitespace,
FirstNonWhitespace { display_lines: bool },
CurrentLine,
StartOfLine,
EndOfLine,
StartOfLine { display_lines: bool },
EndOfLine { display_lines: bool },
StartOfParagraph,
EndOfParagraph,
StartOfDocument,
@ -62,6 +62,41 @@ struct PreviousWordStart {
ignore_punctuation: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct Up {
#[serde(default)]
display_lines: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct Down {
#[serde(default)]
display_lines: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct FirstNonWhitespace {
#[serde(default)]
display_lines: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct EndOfLine {
#[serde(default)]
display_lines: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct StartOfLine {
#[serde(default)]
display_lines: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
struct RepeatFind {
#[serde(default)]
@ -73,12 +108,7 @@ actions!(
[
Left,
Backspace,
Down,
Up,
Right,
FirstNonWhitespace,
StartOfLine,
EndOfLine,
CurrentLine,
StartOfParagraph,
EndOfParagraph,
@ -90,20 +120,63 @@ actions!(
);
impl_actions!(
vim,
[NextWordStart, NextWordEnd, PreviousWordStart, RepeatFind]
[
NextWordStart,
NextWordEnd,
PreviousWordStart,
RepeatFind,
Up,
Down,
FirstNonWhitespace,
EndOfLine,
StartOfLine,
]
);
pub fn init(cx: &mut AppContext) {
cx.add_action(|_: &mut Workspace, _: &Left, cx: _| motion(Motion::Left, cx));
cx.add_action(|_: &mut Workspace, _: &Backspace, cx: _| motion(Motion::Backspace, cx));
cx.add_action(|_: &mut Workspace, _: &Down, cx: _| motion(Motion::Down, cx));
cx.add_action(|_: &mut Workspace, _: &Up, cx: _| motion(Motion::Up, cx));
cx.add_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx));
cx.add_action(|_: &mut Workspace, _: &FirstNonWhitespace, cx: _| {
motion(Motion::FirstNonWhitespace, cx)
cx.add_action(|_: &mut Workspace, action: &Down, cx: _| {
motion(
Motion::Down {
display_lines: action.display_lines,
},
cx,
)
});
cx.add_action(|_: &mut Workspace, action: &Up, cx: _| {
motion(
Motion::Up {
display_lines: action.display_lines,
},
cx,
)
});
cx.add_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx));
cx.add_action(|_: &mut Workspace, action: &FirstNonWhitespace, cx: _| {
motion(
Motion::FirstNonWhitespace {
display_lines: action.display_lines,
},
cx,
)
});
cx.add_action(|_: &mut Workspace, action: &StartOfLine, cx: _| {
motion(
Motion::StartOfLine {
display_lines: action.display_lines,
},
cx,
)
});
cx.add_action(|_: &mut Workspace, action: &EndOfLine, cx: _| {
motion(
Motion::EndOfLine {
display_lines: action.display_lines,
},
cx,
)
});
cx.add_action(|_: &mut Workspace, _: &StartOfLine, cx: _| motion(Motion::StartOfLine, cx));
cx.add_action(|_: &mut Workspace, _: &EndOfLine, cx: _| motion(Motion::EndOfLine, cx));
cx.add_action(|_: &mut Workspace, _: &CurrentLine, cx: _| motion(Motion::CurrentLine, cx));
cx.add_action(|_: &mut Workspace, _: &StartOfParagraph, cx: _| {
motion(Motion::StartOfParagraph, cx)
@ -147,9 +220,9 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
let times = Vim::update(cx, |vim, cx| vim.pop_number_operator(cx));
let operator = Vim::read(cx).active_operator();
match Vim::read(cx).state.mode {
match Vim::read(cx).state().mode {
Mode::Normal => normal_motion(motion, operator, times, cx),
Mode::Visual { .. } => visual_motion(motion, times, cx),
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_motion(motion, times, cx),
Mode::Insert => {
// Shouldn't execute a motion in insert mode. Ignoring
}
@ -158,7 +231,7 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
}
fn repeat_motion(backwards: bool, cx: &mut WindowContext) {
let find = match Vim::read(cx).state.last_find.clone() {
let find = match Vim::read(cx).workspace_state.last_find.clone() {
Some(Motion::FindForward { before, text }) => {
if backwards {
Motion::FindBackward {
@ -192,19 +265,25 @@ impl Motion {
pub fn linewise(&self) -> bool {
use Motion::*;
match self {
Down | Up | StartOfDocument | EndOfDocument | CurrentLine | NextLineStart
| StartOfParagraph | EndOfParagraph => true,
EndOfLine
Down { .. }
| Up { .. }
| StartOfDocument
| EndOfDocument
| CurrentLine
| NextLineStart
| StartOfParagraph
| EndOfParagraph => true,
EndOfLine { .. }
| NextWordEnd { .. }
| Matching
| FindForward { .. }
| Left
| Backspace
| Right
| StartOfLine
| StartOfLine { .. }
| NextWordStart { .. }
| PreviousWordStart { .. }
| FirstNonWhitespace
| FirstNonWhitespace { .. }
| FindBackward { .. } => false,
}
}
@ -213,21 +292,21 @@ impl Motion {
use Motion::*;
match self {
StartOfDocument | EndOfDocument | CurrentLine => true,
Down
| Up
| EndOfLine
Down { .. }
| Up { .. }
| EndOfLine { .. }
| NextWordEnd { .. }
| Matching
| FindForward { .. }
| Left
| Backspace
| Right
| StartOfLine
| StartOfLine { .. }
| StartOfParagraph
| EndOfParagraph
| NextWordStart { .. }
| PreviousWordStart { .. }
| FirstNonWhitespace
| FirstNonWhitespace { .. }
| FindBackward { .. }
| NextLineStart => false,
}
@ -236,12 +315,12 @@ impl Motion {
pub fn inclusive(&self) -> bool {
use Motion::*;
match self {
Down
| Up
Down { .. }
| Up { .. }
| StartOfDocument
| EndOfDocument
| CurrentLine
| EndOfLine
| EndOfLine { .. }
| NextWordEnd { .. }
| Matching
| FindForward { .. }
@ -249,12 +328,12 @@ impl Motion {
Left
| Backspace
| Right
| StartOfLine
| StartOfLine { .. }
| StartOfParagraph
| EndOfParagraph
| NextWordStart { .. }
| PreviousWordStart { .. }
| FirstNonWhitespace
| FirstNonWhitespace { .. }
| FindBackward { .. } => false,
}
}
@ -272,8 +351,18 @@ impl Motion {
let (new_point, goal) = match self {
Left => (left(map, point, times), SelectionGoal::None),
Backspace => (backspace(map, point, times), SelectionGoal::None),
Down => down(map, point, goal, times),
Up => up(map, point, goal, times),
Down {
display_lines: false,
} => down(map, point, goal, times),
Down {
display_lines: true,
} => down_display(map, point, goal, times),
Up {
display_lines: false,
} => up(map, point, goal, times),
Up {
display_lines: true,
} => up_display(map, point, goal, times),
Right => (right(map, point, times), SelectionGoal::None),
NextWordStart { ignore_punctuation } => (
next_word_start(map, point, *ignore_punctuation, times),
@ -287,9 +376,17 @@ impl Motion {
previous_word_start(map, point, *ignore_punctuation, times),
SelectionGoal::None,
),
FirstNonWhitespace => (first_non_whitespace(map, point), SelectionGoal::None),
StartOfLine => (start_of_line(map, point), SelectionGoal::None),
EndOfLine => (end_of_line(map, point), SelectionGoal::None),
FirstNonWhitespace { display_lines } => (
first_non_whitespace(map, *display_lines, point),
SelectionGoal::None,
),
StartOfLine { display_lines } => (
start_of_line(map, *display_lines, point),
SelectionGoal::None,
),
EndOfLine { display_lines } => {
(end_of_line(map, *display_lines, point), SelectionGoal::None)
}
StartOfParagraph => (
movement::start_of_paragraph(map, point, times),
SelectionGoal::None,
@ -298,7 +395,7 @@ impl Motion {
map.clip_at_line_end(movement::end_of_paragraph(map, point, times)),
SelectionGoal::None,
),
CurrentLine => (end_of_line(map, point), SelectionGoal::None),
CurrentLine => (end_of_line(map, false, point), SelectionGoal::None),
StartOfDocument => (start_of_document(map, point, times), SelectionGoal::None),
EndOfDocument => (
end_of_document(map, point, maybe_times),
@ -399,6 +496,33 @@ fn backspace(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> Di
}
fn down(
map: &DisplaySnapshot,
point: DisplayPoint,
mut goal: SelectionGoal,
times: usize,
) -> (DisplayPoint, SelectionGoal) {
let start = map.display_point_to_fold_point(point, Bias::Left);
let goal_column = match goal {
SelectionGoal::Column(column) => column,
SelectionGoal::ColumnRange { end, .. } => end,
_ => {
goal = SelectionGoal::Column(start.column());
start.column()
}
};
let new_row = cmp::min(
start.row() + times as u32,
map.buffer_snapshot.max_point().row,
);
let new_col = cmp::min(goal_column, map.fold_snapshot.line_len(new_row));
let point = map.fold_point_to_display_point(FoldPoint::new(new_row, new_col));
(map.clip_point(point, Bias::Left), goal)
}
fn down_display(
map: &DisplaySnapshot,
mut point: DisplayPoint,
mut goal: SelectionGoal,
@ -407,10 +531,35 @@ fn down(
for _ in 0..times {
(point, goal) = movement::down(map, point, goal, true);
}
(point, goal)
}
fn up(
pub(crate) fn up(
map: &DisplaySnapshot,
point: DisplayPoint,
mut goal: SelectionGoal,
times: usize,
) -> (DisplayPoint, SelectionGoal) {
let start = map.display_point_to_fold_point(point, Bias::Left);
let goal_column = match goal {
SelectionGoal::Column(column) => column,
SelectionGoal::ColumnRange { end, .. } => end,
_ => {
goal = SelectionGoal::Column(start.column());
start.column()
}
};
let new_row = start.row().saturating_sub(times as u32);
let new_col = cmp::min(goal_column, map.fold_snapshot.line_len(new_row));
let point = map.fold_point_to_display_point(FoldPoint::new(new_row, new_col));
(map.clip_point(point, Bias::Left), goal)
}
fn up_display(
map: &DisplaySnapshot,
mut point: DisplayPoint,
mut goal: SelectionGoal,
@ -419,6 +568,7 @@ fn up(
for _ in 0..times {
(point, goal) = movement::up(map, point, goal, true);
}
(point, goal)
}
@ -509,8 +659,12 @@ fn previous_word_start(
point
}
fn first_non_whitespace(map: &DisplaySnapshot, from: DisplayPoint) -> DisplayPoint {
let mut last_point = DisplayPoint::new(from.row(), 0);
fn first_non_whitespace(
map: &DisplaySnapshot,
display_lines: bool,
from: DisplayPoint,
) -> DisplayPoint {
let mut last_point = start_of_line(map, display_lines, from);
let scope = map.buffer_snapshot.language_scope_at(from.to_point(map));
for (ch, point) in map.chars_at(last_point) {
if ch == '\n' {
@ -527,12 +681,31 @@ fn first_non_whitespace(map: &DisplaySnapshot, from: DisplayPoint) -> DisplayPoi
map.clip_point(last_point, Bias::Left)
}
fn start_of_line(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
map.prev_line_boundary(point.to_point(map)).1
pub(crate) fn start_of_line(
map: &DisplaySnapshot,
display_lines: bool,
point: DisplayPoint,
) -> DisplayPoint {
if display_lines {
map.clip_point(DisplayPoint::new(point.row(), 0), Bias::Right)
} else {
map.prev_line_boundary(point.to_point(map)).1
}
}
fn end_of_line(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
map.clip_point(map.next_line_boundary(point.to_point(map)).1, Bias::Left)
pub(crate) fn end_of_line(
map: &DisplaySnapshot,
display_lines: bool,
point: DisplayPoint,
) -> DisplayPoint {
if display_lines {
map.clip_point(
DisplayPoint::new(point.row(), map.line_len(point.row())),
Bias::Left,
)
} else {
map.clip_point(map.next_line_boundary(point.to_point(map)).1, Bias::Left)
}
}
fn start_of_document(map: &DisplaySnapshot, point: DisplayPoint, line: usize) -> DisplayPoint {
@ -654,8 +827,8 @@ fn find_backward(
}
fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint {
let new_row = (point.row() + times as u32).min(map.max_buffer_row());
map.clip_point(DisplayPoint::new(new_row, 0), Bias::Left)
let correct_line = down(map, point, SelectionGoal::None, times).0;
first_non_whitespace(map, false, correct_line)
}
#[cfg(test)]
@ -803,4 +976,12 @@ mod test {
cx.simulate_shared_keystrokes([","]).await;
cx.assert_shared_state("one two thˇree four").await;
}
#[gpui::test]
async fn test_next_line_start(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇone\n two\nthree").await;
cx.simulate_shared_keystrokes(["enter"]).await;
cx.assert_shared_state("one\n ˇtwo\nthree").await;
}
}