Task attempt 19940407-2ae9-4850-b151-834c900e23e3 - Final changes
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
use anyhow::anyhow;
|
||||
use chrono::{DateTime, Utc};
|
||||
use git2::build::CheckoutBuilder;
|
||||
use git2::{Error as GitError, MergeOptions, Oid, RebaseOptions, Repository};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, SqlitePool, Type};
|
||||
use std::path::Path;
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::error;
|
||||
use ts_rs::TS;
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -690,33 +689,16 @@ impl TaskAttempt {
|
||||
String::new() // File was deleted
|
||||
};
|
||||
|
||||
// Generate diff chunks using dissimilar
|
||||
// Generate line-based diff chunks
|
||||
if old_content != new_content {
|
||||
let chunks = dissimilar::diff(&old_content, &new_content);
|
||||
let mut diff_chunks = Vec::new();
|
||||
let diff_chunks = Self::generate_line_based_diff(&old_content, &new_content);
|
||||
|
||||
for chunk in chunks {
|
||||
let diff_chunk = match chunk {
|
||||
dissimilar::Chunk::Equal(text) => DiffChunk {
|
||||
chunk_type: DiffChunkType::Equal,
|
||||
content: text.to_string(),
|
||||
},
|
||||
dissimilar::Chunk::Delete(text) => DiffChunk {
|
||||
chunk_type: DiffChunkType::Delete,
|
||||
content: text.to_string(),
|
||||
},
|
||||
dissimilar::Chunk::Insert(text) => DiffChunk {
|
||||
chunk_type: DiffChunkType::Insert,
|
||||
content: text.to_string(),
|
||||
},
|
||||
};
|
||||
diff_chunks.push(diff_chunk);
|
||||
if !diff_chunks.is_empty() {
|
||||
files.push(FileDiff {
|
||||
path: path_str.to_string(),
|
||||
chunks: diff_chunks,
|
||||
});
|
||||
}
|
||||
|
||||
files.push(FileDiff {
|
||||
path: path_str.to_string(),
|
||||
chunks: diff_chunks,
|
||||
});
|
||||
}
|
||||
}
|
||||
true // Continue processing
|
||||
@@ -729,6 +711,97 @@ impl TaskAttempt {
|
||||
Ok(WorktreeDiff { files })
|
||||
}
|
||||
|
||||
/// Generate line-based diff chunks for better display
|
||||
pub fn generate_line_based_diff(old_content: &str, new_content: &str) -> Vec<DiffChunk> {
|
||||
let old_lines: Vec<&str> = old_content.lines().collect();
|
||||
let new_lines: Vec<&str> = new_content.lines().collect();
|
||||
let mut chunks = Vec::new();
|
||||
|
||||
// Use a simple line-by-line comparison algorithm
|
||||
let mut old_idx = 0;
|
||||
let mut new_idx = 0;
|
||||
|
||||
while old_idx < old_lines.len() || new_idx < new_lines.len() {
|
||||
if old_idx < old_lines.len() && new_idx < new_lines.len() {
|
||||
let old_line = old_lines[old_idx];
|
||||
let new_line = new_lines[new_idx];
|
||||
|
||||
if old_line == new_line {
|
||||
// Lines are identical
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Equal,
|
||||
content: format!("{}\n", old_line),
|
||||
});
|
||||
old_idx += 1;
|
||||
new_idx += 1;
|
||||
} else {
|
||||
// Lines are different - look ahead to see if this is a modification, insertion, or deletion
|
||||
let mut found_match = false;
|
||||
|
||||
// Check if the new line appears later in old lines (deletion)
|
||||
for look_ahead in (old_idx + 1)..std::cmp::min(old_idx + 5, old_lines.len()) {
|
||||
if old_lines[look_ahead] == new_line {
|
||||
// Found the new line later in old, so old_line was deleted
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Delete,
|
||||
content: format!("{}\n", old_line),
|
||||
});
|
||||
old_idx += 1;
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !found_match {
|
||||
// Check if the old line appears later in new lines (insertion)
|
||||
for look_ahead in (new_idx + 1)..std::cmp::min(new_idx + 5, new_lines.len()) {
|
||||
if new_lines[look_ahead] == old_line {
|
||||
// Found the old line later in new, so new_line was inserted
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Insert,
|
||||
content: format!("{}\n", new_line),
|
||||
});
|
||||
new_idx += 1;
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found_match {
|
||||
// Lines are different - treat as modification (delete old, insert new)
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Delete,
|
||||
content: format!("{}\n", old_line),
|
||||
});
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Insert,
|
||||
content: format!("{}\n", new_line),
|
||||
});
|
||||
old_idx += 1;
|
||||
new_idx += 1;
|
||||
}
|
||||
}
|
||||
} else if old_idx < old_lines.len() {
|
||||
// Remaining old lines (deletions)
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Delete,
|
||||
content: format!("{}\n", old_lines[old_idx]),
|
||||
});
|
||||
old_idx += 1;
|
||||
} else {
|
||||
// Remaining new lines (insertions)
|
||||
chunks.push(DiffChunk {
|
||||
chunk_type: DiffChunkType::Insert,
|
||||
content: format!("{}\n", new_lines[new_idx]),
|
||||
});
|
||||
new_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
chunks
|
||||
}
|
||||
|
||||
/// Get the branch status for this task attempt (ahead/behind main)
|
||||
pub async fn get_branch_status(
|
||||
pool: &SqlitePool,
|
||||
@@ -836,7 +909,7 @@ impl TaskAttempt {
|
||||
let mut last_oid: Option<Oid> = None;
|
||||
while let Some(res) = reb.next() {
|
||||
match res {
|
||||
Ok(op) => {
|
||||
Ok(_op) => {
|
||||
let new_oid = reb.commit(None, &sig, None)?;
|
||||
last_oid = Some(new_oid);
|
||||
}
|
||||
@@ -863,7 +936,7 @@ impl TaskAttempt {
|
||||
repo.checkout_head(Some(CheckoutBuilder::new().force()))?;
|
||||
|
||||
// 🔟 final check
|
||||
let final_oid = repo.head()?.peel_to_commit()?.id();
|
||||
let _final_oid = repo.head()?.peel_to_commit()?.id();
|
||||
|
||||
Ok(main_oid.to_string())
|
||||
}
|
||||
|
||||
51
backend/src/models/test_diff.rs
Normal file
51
backend/src/models/test_diff.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::task_attempt::{TaskAttempt, DiffChunkType};
|
||||
|
||||
#[test]
|
||||
fn test_line_based_diff() {
|
||||
let old_content = "line 1\nline 2\nline 3\n";
|
||||
let new_content = "line 1\nmodified line 2\nline 3\n";
|
||||
|
||||
let chunks = TaskAttempt::generate_line_based_diff(old_content, new_content);
|
||||
|
||||
// Should have: equal, delete, insert, equal
|
||||
assert_eq!(chunks.len(), 4);
|
||||
|
||||
// First chunk should be equal
|
||||
assert_eq!(chunks[0].chunk_type, DiffChunkType::Equal);
|
||||
assert_eq!(chunks[0].content, "line 1\n");
|
||||
|
||||
// Second chunk should be delete
|
||||
assert_eq!(chunks[1].chunk_type, DiffChunkType::Delete);
|
||||
assert_eq!(chunks[1].content, "line 2\n");
|
||||
|
||||
// Third chunk should be insert
|
||||
assert_eq!(chunks[2].chunk_type, DiffChunkType::Insert);
|
||||
assert_eq!(chunks[2].content, "modified line 2\n");
|
||||
|
||||
// Fourth chunk should be equal
|
||||
assert_eq!(chunks[3].chunk_type, DiffChunkType::Equal);
|
||||
assert_eq!(chunks[3].content, "line 3\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_insertion() {
|
||||
let old_content = "line 1\nline 3\n";
|
||||
let new_content = "line 1\nline 2\nline 3\n";
|
||||
|
||||
let chunks = TaskAttempt::generate_line_based_diff(old_content, new_content);
|
||||
|
||||
// Should have: equal, insert, equal
|
||||
assert_eq!(chunks.len(), 3);
|
||||
|
||||
assert_eq!(chunks[0].chunk_type, DiffChunkType::Equal);
|
||||
assert_eq!(chunks[0].content, "line 1\n");
|
||||
|
||||
assert_eq!(chunks[1].chunk_type, DiffChunkType::Insert);
|
||||
assert_eq!(chunks[1].content, "line 2\n");
|
||||
|
||||
assert_eq!(chunks[2].chunk_type, DiffChunkType::Equal);
|
||||
assert_eq!(chunks[2].content, "line 3\n");
|
||||
}
|
||||
}
|
||||
49
test_diff_logic.py
Normal file
49
test_diff_logic.py
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
def test_diff_logic():
|
||||
"""Test the logic of our line-based diff algorithm"""
|
||||
|
||||
# Test case 1: Line modification
|
||||
old_content = "line 1\nline 2\nline 3\n"
|
||||
new_content = "line 1\nmodified line 2\nline 3\n"
|
||||
|
||||
old_lines = old_content.split('\n')[:-1] # Remove empty last element
|
||||
new_lines = new_content.split('\n')[:-1]
|
||||
|
||||
print("Test 1 - Line modification:")
|
||||
print(f"Old lines: {old_lines}")
|
||||
print(f"New lines: {new_lines}")
|
||||
|
||||
# Expected chunks: Equal, Delete, Insert, Equal
|
||||
expected_chunks = [
|
||||
("Equal", "line 1\n"),
|
||||
("Delete", "line 2\n"),
|
||||
("Insert", "modified line 2\n"),
|
||||
("Equal", "line 3\n")
|
||||
]
|
||||
|
||||
print(f"Expected chunks: {expected_chunks}")
|
||||
print()
|
||||
|
||||
# Test case 2: Line insertion
|
||||
old_content = "line 1\nline 3\n"
|
||||
new_content = "line 1\nline 2\nline 3\n"
|
||||
|
||||
old_lines = old_content.split('\n')[:-1]
|
||||
new_lines = new_content.split('\n')[:-1]
|
||||
|
||||
print("Test 2 - Line insertion:")
|
||||
print(f"Old lines: {old_lines}")
|
||||
print(f"New lines: {new_lines}")
|
||||
|
||||
# Expected chunks: Equal, Insert, Equal
|
||||
expected_chunks = [
|
||||
("Equal", "line 1\n"),
|
||||
("Insert", "line 2\n"),
|
||||
("Equal", "line 3\n")
|
||||
]
|
||||
|
||||
print(f"Expected chunks: {expected_chunks}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_diff_logic()
|
||||
Reference in New Issue
Block a user