Implement Phase 1.1: Delete Python skeleton and create C++/TypeScript architecture

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-12-25 08:37:29 +00:00
parent 155a8b896c
commit 15e40ffd4c
36 changed files with 792 additions and 1112 deletions
+83
View File
@@ -0,0 +1,83 @@
/**
* @file main.cpp
* @brief Command-line interface for WizardMerge
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include "wizardmerge/merge/three_way_merge.h"
using namespace wizardmerge::merge;
/**
* @brief Read lines from a file
*/
std::vector<std::string> read_file(const std::string& filename) {
std::vector<std::string> lines;
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
lines.push_back(line);
}
return lines;
}
/**
* @brief Write lines to a file
*/
void write_file(const std::string& filename, const std::vector<Line>& lines) {
std::ofstream file(filename);
for (const auto& line : lines) {
file << line.content << '\n';
}
}
int main(int argc, char* argv[]) {
if (argc != 5) {
std::cerr << "Usage: " << argv[0] << " <base> <ours> <theirs> <output>\n";
std::cerr << "Performs three-way merge on three file versions.\n";
return 1;
}
std::string base_file = argv[1];
std::string ours_file = argv[2];
std::string theirs_file = argv[3];
std::string output_file = argv[4];
std::cout << "WizardMerge - Intelligent Merge Conflict Resolution\n";
std::cout << "===================================================\n";
std::cout << "Base: " << base_file << '\n';
std::cout << "Ours: " << ours_file << '\n';
std::cout << "Theirs: " << theirs_file << '\n';
std::cout << "Output: " << output_file << '\n';
std::cout << '\n';
// Read input files
auto base = read_file(base_file);
auto ours = read_file(ours_file);
auto theirs = read_file(theirs_file);
// Perform merge
auto result = three_way_merge(base, ours, theirs);
// Auto-resolve simple conflicts
result = auto_resolve(result);
// Write output
write_file(output_file, result.merged_lines);
// Report results
if (result.has_conflicts()) {
std::cout << "Merge completed with " << result.conflicts.size()
<< " conflict(s).\n";
std::cout << "Please review and resolve conflicts in: " << output_file << '\n';
return 1;
} else {
std::cout << "Merge completed successfully with no conflicts.\n";
return 0;
}
}
+117
View File
@@ -0,0 +1,117 @@
/**
* @file three_way_merge.cpp
* @brief Implementation of three-way merge algorithm
*/
#include "wizardmerge/merge/three_way_merge.h"
#include <algorithm>
namespace wizardmerge {
namespace merge {
namespace {
/**
* @brief Check if two lines are effectively equal (ignoring whitespace).
*/
bool lines_equal_ignore_whitespace(const std::string& a, const std::string& b) {
auto trim = [](const std::string& s) {
size_t start = s.find_first_not_of(" \t\n\r");
size_t end = s.find_last_not_of(" \t\n\r");
if (start == std::string::npos) return std::string();
return s.substr(start, end - start + 1);
};
return trim(a) == trim(b);
}
} // namespace
MergeResult three_way_merge(
const std::vector<std::string>& base,
const std::vector<std::string>& ours,
const std::vector<std::string>& theirs
) {
MergeResult result;
// Simple line-by-line comparison for initial implementation
// This is a placeholder - full algorithm will use dependency analysis
size_t max_len = std::max({base.size(), ours.size(), theirs.size()});
for (size_t i = 0; i < max_len; ++i) {
std::string base_line = (i < base.size()) ? base[i] : "";
std::string our_line = (i < ours.size()) ? ours[i] : "";
std::string their_line = (i < theirs.size()) ? theirs[i] : "";
// Case 1: All three are the same - use as-is
if (base_line == our_line && base_line == their_line) {
result.merged_lines.push_back({base_line, Line::BASE});
}
// Case 2: Base == Ours, but Theirs changed - use theirs
else if (base_line == our_line && base_line != their_line) {
result.merged_lines.push_back({their_line, Line::THEIRS});
}
// Case 3: Base == Theirs, but Ours changed - use ours
else if (base_line == their_line && base_line != our_line) {
result.merged_lines.push_back({our_line, Line::OURS});
}
// Case 4: Ours == Theirs, but different from Base - use the common change
else if (our_line == their_line && our_line != base_line) {
result.merged_lines.push_back({our_line, Line::MERGED});
}
// Case 5: All different - conflict
else {
Conflict conflict;
conflict.start_line = result.merged_lines.size();
conflict.base_lines.push_back({base_line, Line::BASE});
conflict.our_lines.push_back({our_line, Line::OURS});
conflict.their_lines.push_back({their_line, Line::THEIRS});
conflict.end_line = result.merged_lines.size();
result.conflicts.push_back(conflict);
// Add conflict markers
result.merged_lines.push_back({"<<<<<<< OURS", Line::MERGED});
result.merged_lines.push_back({our_line, Line::OURS});
result.merged_lines.push_back({"=======", Line::MERGED});
result.merged_lines.push_back({their_line, Line::THEIRS});
result.merged_lines.push_back({">>>>>>> THEIRS", Line::MERGED});
}
}
return result;
}
MergeResult auto_resolve(const MergeResult& result) {
MergeResult resolved = result;
// Auto-resolve whitespace-only differences
std::vector<Conflict> remaining_conflicts;
for (const auto& conflict : result.conflicts) {
bool can_resolve = false;
// Check if differences are whitespace-only
if (conflict.our_lines.size() == conflict.their_lines.size()) {
can_resolve = true;
for (size_t i = 0; i < conflict.our_lines.size(); ++i) {
if (!lines_equal_ignore_whitespace(
conflict.our_lines[i].content,
conflict.their_lines[i].content)) {
can_resolve = false;
break;
}
}
}
if (!can_resolve) {
remaining_conflicts.push_back(conflict);
}
}
resolved.conflicts = remaining_conflicts;
return resolved;
}
} // namespace merge
} // namespace wizardmerge