Allow the assistant to suggest edits to files in the project (#11993)
### Todo * [x] tuck the new system prompt away somehow * for now, we're treating it as built-in, and not editable. once we have a way to fold away default prompts, let's make it a default prompt. * [x] when applying edits, re-parse the edit from the latest content of the assistant buffer (to allow for manual editing of edits) * [x] automatically adjust the indentation of edits suggested by the assistant * [x] fix edit row highlights persisting even when assistant messages with edits are deleted * ~adjust the fuzzy search to allow for small errors in the old text, using some string similarity routine~ We decided to defer the fuzzy searching thing to a separate PR, since it's a little bit involved, and the current functionality works well enough to be worth landing. A couple of notes on the fuzzy searching: * sometimes the assistant accidentally omits line breaks from the text that it wants to replace * when the old text has hallucinations, the new text often contains the same hallucinations. so we'll probably need to use a more fine-grained editing strategy where we perform a character-wise diff of the old and new text as reported by the assistant, and then adjust that diff so that it can be applied to the actual buffer text Release Notes: - Added the ability to request edits to project files using the assistant panel. --------- Co-authored-by: Antonio Scandurra <me@as-cii.com> Co-authored-by: Marshall <marshall@zed.dev> Co-authored-by: Antonio <antonio@zed.dev> Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
parent
4386268a94
commit
84affa96ff
11 changed files with 912 additions and 181 deletions
|
@ -617,6 +617,14 @@ impl<'a> Chunks<'a> {
|
|||
let end = self.range.end - chunk_start;
|
||||
Some(&chunk.0[start..chunk.0.len().min(end)])
|
||||
}
|
||||
|
||||
pub fn lines(self) -> Lines<'a> {
|
||||
Lines {
|
||||
chunks: self,
|
||||
current_line: String::new(),
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Chunks<'a> {
|
||||
|
@ -714,6 +722,49 @@ impl<'a> io::Read for Bytes<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Lines<'a> {
|
||||
chunks: Chunks<'a>,
|
||||
current_line: String,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl<'a> Lines<'a> {
|
||||
pub fn next(&mut self) -> Option<&str> {
|
||||
if self.done {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.current_line.clear();
|
||||
|
||||
while let Some(chunk) = self.chunks.peek() {
|
||||
let mut lines = chunk.split('\n').peekable();
|
||||
while let Some(line) = lines.next() {
|
||||
self.current_line.push_str(line);
|
||||
if lines.peek().is_some() {
|
||||
self.chunks
|
||||
.seek(self.chunks.offset() + line.len() + "\n".len());
|
||||
return Some(&self.current_line);
|
||||
}
|
||||
}
|
||||
|
||||
self.chunks.next();
|
||||
}
|
||||
|
||||
self.done = true;
|
||||
Some(&self.current_line)
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, offset: usize) {
|
||||
self.chunks.seek(offset);
|
||||
self.current_line.clear();
|
||||
self.done = false;
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
self.chunks.offset()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct Chunk(ArrayString<{ 2 * CHUNK_BASE }>);
|
||||
|
||||
|
@ -1288,6 +1339,24 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines() {
|
||||
let rope = Rope::from("abc\ndefg\nhi");
|
||||
let mut lines = rope.chunks().lines();
|
||||
assert_eq!(lines.next(), Some("abc"));
|
||||
assert_eq!(lines.next(), Some("defg"));
|
||||
assert_eq!(lines.next(), Some("hi"));
|
||||
assert_eq!(lines.next(), None);
|
||||
|
||||
let rope = Rope::from("abc\ndefg\nhi\n");
|
||||
let mut lines = rope.chunks().lines();
|
||||
assert_eq!(lines.next(), Some("abc"));
|
||||
assert_eq!(lines.next(), Some("defg"));
|
||||
assert_eq!(lines.next(), Some("hi"));
|
||||
assert_eq!(lines.next(), Some(""));
|
||||
assert_eq!(lines.next(), None);
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
fn test_random_rope(mut rng: StdRng) {
|
||||
let operations = env::var("OPERATIONS")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue