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

View File

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

View File

@@ -237,7 +237,7 @@ fn assert_editor_active_edit_completion(
.as_ref() .as_ref()
.expect("editor has no active completion"); .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); assert(editor.buffer().read(cx).snapshot(cx), edits);
} else { } else {
panic!("expected edit completion"); panic!("expected edit completion");