Compare commits

...

8 Commits

Author SHA1 Message Date
Bennet Bo Fenner
7a8965ccc7 cleanup 2024-12-12 12:38:55 +01:00
Bennet Bo Fenner
3364cd9889 remove unrelated changes 2024-12-12 12:26:59 +01:00
Bennet Bo Fenner
b6ac26b1e2 fix tests 2024-12-12 12:23:39 +01:00
Bennet Bo Fenner
9ab17f5b32 Merge branch 'main' into zeta-syntax-highlighting-diff 2024-12-12 12:09:04 +01:00
Bennet Bo Fenner
d5f5a615e8 move branching buffer to editor 2024-12-12 12:07:25 +01:00
Bennet Bo Fenner
f4f618c9cb Show existing text until the end of the last line 2024-12-12 11:54:15 +01:00
Bennet Bo Fenner
71b4d98367 WIP 2024-12-12 10:43:46 +01:00
Bennet Bo Fenner
77328e8300 WIP 2024-12-12 00:57:56 +01:00
3 changed files with 151 additions and 53 deletions

View File

@@ -445,7 +445,10 @@ pub fn make_inlay_hints_style(cx: &WindowContext) -> HighlightStyle {
type CompletionId = usize;
enum InlineCompletion {
Edit(Vec<(Range<Anchor>, String)>),
Edit {
edits: Vec<(Range<Anchor>, String)>,
applied_edits_buffer: Model<Buffer>,
},
Move(Anchor),
}
@@ -4517,7 +4520,7 @@ impl Editor {
selections.select_anchor_ranges([position..position]);
});
}
InlineCompletion::Edit(edits) => {
InlineCompletion::Edit { edits, .. } => {
if let Some(provider) = self.inline_completion_provider() {
provider.accept(cx);
}
@@ -4564,7 +4567,7 @@ impl Editor {
selections.select_anchor_ranges([position..position]);
});
}
InlineCompletion::Edit(edits) => {
InlineCompletion::Edit { edits, .. } => {
if edits.len() == 1 && edits[0].0.start == edits[0].0.end {
let text = edits[0].1.as_str();
let mut partial_completion = text
@@ -4681,6 +4684,7 @@ impl Editor {
let completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
let edits = completion
.edits
.clone()
.into_iter()
.map(|(range, new_text)| {
(
@@ -4714,13 +4718,13 @@ impl Editor {
let mut inlay_ids = Vec::new();
let invalidation_row_range;
let completion;
let editor_completion;
if cursor_row < edit_start_row {
invalidation_row_range = cursor_row..edit_end_row;
completion = InlineCompletion::Move(first_edit_start);
editor_completion = InlineCompletion::Move(first_edit_start);
} else if cursor_row > edit_end_row {
invalidation_row_range = edit_start_row..cursor_row;
completion = InlineCompletion::Move(first_edit_start);
editor_completion = InlineCompletion::Move(first_edit_start);
} else {
if edits
.iter()
@@ -4751,7 +4755,15 @@ impl Editor {
}
invalidation_row_range = edit_start_row..edit_end_row;
completion = InlineCompletion::Edit(edits);
let applied_edits_buffer = buffer.update(cx, |buffer, cx| buffer.branch(cx));
applied_edits_buffer.update(cx, |buffer, cx| {
buffer.edit(completion.edits, None, cx);
});
editor_completion = InlineCompletion::Edit {
edits,
applied_edits_buffer,
};
};
let invalidation_range = multibuffer
@@ -4763,7 +4775,7 @@ impl Editor {
self.active_inline_completion = Some(InlineCompletionState {
inlay_ids,
completion,
completion: editor_completion,
invalidation_range,
});
cx.notify();

View File

@@ -33,10 +33,10 @@ use gpui::{
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity,
FontId, GlobalElementId, HighlightStyle, Hitbox, Hsla, InteractiveElement, IntoElement, Length,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
StatefulInteractiveElement, Style, Styled, TextRun, TextStyleRefinement, View, ViewContext,
WeakView, WindowContext,
Model, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString,
Size, StatefulInteractiveElement, Style, Styled, TextRun, TextStyleRefinement, View,
ViewContext, WeakView, WindowContext,
};
use gpui::{ClickEvent, Subscription};
use itertools::Itertools;
@@ -45,7 +45,7 @@ use language::{
IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings,
ShowWhitespaceSetting,
},
ChunkRendererContext,
Buffer, ChunkRendererContext,
};
use lsp::DiagnosticSeverity;
use multi_buffer::{
@@ -2818,7 +2818,10 @@ impl EditorElement {
Some(element)
}
}
InlineCompletion::Edit(edits) => {
InlineCompletion::Edit {
edits,
applied_edits_buffer,
} => {
let edit_start = edits
.first()
.unwrap()
@@ -2842,7 +2845,12 @@ impl EditorElement {
return None;
}
let (text, highlights) = inline_completion_popover_text(editor_snapshot, edits, cx);
let (text, highlights) = inline_completion_popover_text(
editor_snapshot,
edits,
applied_edits_buffer.clone(),
cx,
);
let longest_row =
editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
@@ -4309,54 +4317,89 @@ impl EditorElement {
fn inline_completion_popover_text(
editor_snapshot: &EditorSnapshot,
edits: &Vec<(Range<Anchor>, String)>,
applied_edits_buffer: Model<Buffer>,
cx: &WindowContext,
) -> (String, Vec<(Range<usize>, HighlightStyle)>) {
let edit_start = edits
use text::{ToOffset as _, ToPoint as _};
let mut text = String::new();
let mut highlights = Vec::new();
let snapshot = applied_edits_buffer.read(cx).snapshot();
let mut start = edits
.first()
.unwrap()
.0
.start
.to_display_point(editor_snapshot);
let mut text = String::new();
let mut offset = DisplayPoint::new(edit_start.row(), 0).to_offset(editor_snapshot, Bias::Left);
let mut highlights = Vec::new();
.bias_left(&editor_snapshot.buffer_snapshot)
.text_anchor
.to_point(&snapshot);
start.column = 0;
let mut offset = text::ToOffset::to_offset(&start, &snapshot);
for (old_range, new_text) in edits {
let old_offset_range = old_range.to_offset(&editor_snapshot.buffer_snapshot);
text.extend(
editor_snapshot
.buffer_snapshot
.chunks(offset..old_offset_range.start, false)
.map(|chunk| chunk.text),
);
offset = old_offset_range.end;
let edit_new_start = old_range
.start
.bias_left(&editor_snapshot.buffer_snapshot)
.text_anchor
.to_offset(&snapshot);
for chunk in snapshot.chunks(offset..edit_new_start, true) {
let start = text.len();
text.push_str(chunk.text);
let end = text.len();
let start = text.len();
text.push_str(new_text);
let end = text.len();
highlights.push((
start..end,
HighlightStyle {
if let Some(highlight_style) = chunk
.syntax_highlight_id
.and_then(|id| id.style(cx.theme().syntax()))
{
highlights.push((start..end, highlight_style));
}
}
let end_offset = edit_new_start + new_text.len();
for chunk in snapshot.chunks(edit_new_start..end_offset, true) {
let start = text.len();
text.push_str(chunk.text);
let end = text.len();
let mut highlight_style = HighlightStyle {
background_color: Some(cx.theme().status().created_background),
..Default::default()
},
));
};
if let Some(syntax_highlight_style) = chunk
.syntax_highlight_id
.and_then(|id| id.style(cx.theme().syntax()))
{
highlight_style.highlight(syntax_highlight_style);
}
highlights.push((start..end, highlight_style));
}
offset = end_offset;
}
let edit_end = edits
let mut end = edits
.last()
.unwrap()
.0
.end
.to_display_point(editor_snapshot);
let end_of_line = DisplayPoint::new(edit_end.row(), editor_snapshot.line_len(edit_end.row()))
.to_offset(editor_snapshot, Bias::Right);
text.extend(
editor_snapshot
.buffer_snapshot
.chunks(offset..end_of_line, false)
.map(|chunk| chunk.text),
);
.bias_left(&editor_snapshot.buffer_snapshot)
.text_anchor
.to_point(&snapshot);
end.column = snapshot.line_len(end.row);
let end = text::ToOffset::to_offset(&end, &snapshot);
for chunk in snapshot.chunks(offset..end, true) {
let start = text.len();
text.push_str(chunk.text);
let end = text.len();
if let Some(highlight_style) = chunk
.syntax_highlight_id
.and_then(|id| id.style(cx.theme().syntax()))
{
highlights.push((start..end, highlight_style));
}
}
(text, highlights)
}
@@ -6657,7 +6700,7 @@ mod tests {
editor_tests::{init_test, update_test_language_settings},
Editor, MultiBuffer,
};
use gpui::{TestAppContext, VisualTestContext};
use gpui::{AppContext, TestAppContext, VisualTestContext};
use language::language_settings;
use log::info;
use std::num::NonZeroU32;
@@ -7127,7 +7170,12 @@ mod tests {
..snapshot.buffer_snapshot.anchor_before(Point::new(0, 6));
let edits = vec![(edit_range, " beautiful".to_string())];
let (text, highlights) = inline_completion_popover_text(&snapshot, &edits, cx);
let (text, highlights) = inline_completion_popover_text(
&snapshot,
&edits,
create_applied_edits_buffer(editor, edits.clone(), cx),
cx,
);
assert_eq!(text, "Hello, beautiful world!");
assert_eq!(highlights.len(), 1);
@@ -7157,7 +7205,12 @@ mod tests {
"That".to_string(),
)];
let (text, highlights) = inline_completion_popover_text(&snapshot, &edits, cx);
let (text, highlights) = inline_completion_popover_text(
&snapshot,
&edits,
create_applied_edits_buffer(editor, edits.clone(), cx),
cx,
);
assert_eq!(text, "That is a test.");
assert_eq!(highlights.len(), 1);
@@ -7194,7 +7247,12 @@ mod tests {
),
];
let (text, highlights) = inline_completion_popover_text(&snapshot, &edits, cx);
let (text, highlights) = inline_completion_popover_text(
&snapshot,
&edits,
create_applied_edits_buffer(editor, edits.clone(), cx),
cx,
);
assert_eq!(text, "Greetings, world and universe!");
assert_eq!(highlights.len(), 2);
@@ -7244,7 +7302,12 @@ mod tests {
),
];
let (text, highlights) = inline_completion_popover_text(&snapshot, &edits, cx);
let (text, highlights) = inline_completion_popover_text(
&snapshot,
&edits,
create_applied_edits_buffer(editor, edits.clone(), cx),
cx,
);
assert_eq!(text, "Second modified\nNew third line\nFourth updated line");
assert_eq!(highlights.len(), 3);
@@ -7263,6 +7326,29 @@ mod tests {
}
}
fn create_applied_edits_buffer(
editor: &Editor,
edits: Vec<(Range<Anchor>, String)>,
cx: &mut AppContext,
) -> Model<Buffer> {
let buffer = editor
.buffer()
.read(cx)
.as_singleton()
.unwrap()
.update(cx, |buffer, cx| buffer.branch(cx));
buffer.update(cx, |buffer, cx| {
buffer.edit(
edits
.into_iter()
.map(|(range, text)| (range.start.text_anchor..range.end.text_anchor, text)),
None,
cx,
)
});
buffer
}
fn collect_invisibles_from_new_editor(
cx: &mut TestAppContext,
editor_mode: EditorMode,

View File

@@ -237,7 +237,7 @@ fn assert_editor_active_edit_completion(
.as_ref()
.expect("editor has no active completion");
if let InlineCompletion::Edit(edits) = &completion_state.completion {
if let InlineCompletion::Edit { edits, .. } = &completion_state.completion {
assert(editor.buffer().read(cx).snapshot(cx), edits);
} else {
panic!("expected edit completion");