QDiffX is a lightweight, extensible diff viewer widget for Qt.
It is designed to be dropped into existing Qt applications without web views, heavy dependencies, or complex setup.
The project focuses on two core ideas:
- A clean, usable diff UI (inline and side-by-side)
- A pluggable algorithm system so diff logic stays flexible and replaceable
- Synchronous and asynchronous execution for both responsive UIs and immediate results
- A ready-to-use Qt Widgets diff component
- Supports side-by-side and inline diff views
- Built with Qt Widgets (Qt 5.15+ and Qt 6.x)
- Written in C++17
- Can be embedded or extended easily
This is meant to be infrastructure something you don't have to rewrite for every Qt project.
- File managers and sync tools
- IDEs and code editors
- Configuration and settings comparison
- Database and DevOps tools
- Any Qt application that needs to show "what changed"
#include "QDiffWidget.h"
auto* diff = new QDiffX::QDiffWidget(this);
diff->setLeftContent(originalText);
diff->setRightContent(modifiedText);
layout->addWidget(diff);That's it the widget handles rendering, scrolling, and highlighting.
// Side-by-side (default)
diff->setDisplayMode(QDiffX::QDiffWidget::SideBySide);
// Inline
diff->setDisplayMode(QDiffX::QDiffWidget::Inline);QDiffX cleanly separates diff visualization from diff algorithms.
Algorithms are implemented as small, self-contained classes and registered with the system.
- Swap algorithms without touching UI code
- Use simple algorithms for small files
- Plug in advanced algorithms for large or structured content
- Easy to experiment or customize behavior
- Create a class that inherits from
QDiffX::QDiffAlgorithm - Implement:
calculateDiff(...)getName()getDescription()
- Register it with the algorithm manager or registry
registry.registerAlgorithm(
std::make_shared<MyCustomDiffAlgorithm>()
);Once registered, the algorithm appears in the UI automatically and can be selected at runtime.
auto* manager = new QDiffX::QAlgorithmManager(diff);
manager->setSelectionMode(QDiffX::QAlgorithmSelectionMode::Auto);
diff->setAlgorithmManager(manager);Manual selection is also supported if a specific algorithm is required.
Each algorithm declares its capabilities:
- Support for large files
- Unicode and binary content support
- Line-by-line, character-by-character, or word-by-word diffing
- Maximum recommended file size
- Performance complexity estimation
The algorithm manager uses these capabilities for intelligent automatic selection.
QDiffX supports both synchronous and asynchronous diff calculation.
manager->setExecutionMode(QDiffX::QExecutionMode::Asynchronous);
auto future = manager->calculateDiffAsync(leftText, rightText);
// UI remains responsive while calculation runs in backgroundConnect to signals to receive results:
connect(manager, &QDiffX::QAlgorithmManager::diffCalculated,
this, [](const QDiffX::QDiffResult& result) {
if (result.success()) {
// Use the result
}
});manager->setExecutionMode(QDiffX::QExecutionMode::Synchronous);
auto result = manager->calculateDiffSync(leftText, rightText);
if (result.success()) {
// Process immediately
}QDiffX provides comprehensive error handling through typed error codes and detailed error messages.
enum class QAlgorithmManagerError {
None, // No error
AlgorithmNotFound, // Requested algorithm doesn't exist
AlgorithmCreationFailed, // Failed to instantiate algorithm
InvalidAlgorithmId, // Invalid algorithm identifier
DiffExecutionFailed, // Algorithm execution failed
ConfigurationError, // Invalid algorithm configuration
Timeout, // Operation exceeded time limit
OperationCancelled, // User cancelled operation
Unknown // Unexpected error
};auto result = manager->calculateDiffSync(leftText, rightText);
if (!result.success()) {
QString error = result.errorMessage();
qWarning() << "Diff failed:" << error;
// Check specific error type
auto errorType = manager->lastError();
if (errorType == QDiffX::QAlgorithmManagerError::AlgorithmNotFound) {
// Handle missing algorithm
}
}connect(manager, &QDiffX::QAlgorithmManager::errorOccurred,
this, [](QDiffX::QAlgorithmManagerError error, const QString& message) {
qCritical() << "Algorithm error:" << message;
});Configure a fallback algorithm for automatic recovery:
manager->setCurrentAlgorithm("advanced-algorithm");
manager->setFallBackAlgorithm("simple-algorithm");
// If advanced-algorithm fails, simple-algorithm is automatically triedQDiffX is designed with thread safety in mind:
- Algorithm registry uses
QMutexfor concurrent access - Algorithm manager supports asynchronous execution via
QFuture - Safe to call from multiple threads when using the registry
- UI updates are handled on the main thread
Algorithms can be configured at runtime:
// Get current configuration
auto config = manager->getAlgorithmConfiguration("dmp");
// Modify settings
config["timeout"] = 5000;
config["checklines"] = true;
// Apply new configuration
manager->setAlgorithmConfiguration("dmp", config);Configuration changes emit signals for reactive updates:
connect(manager, &QDiffX::QAlgorithmManager::algorithmConfigurationChanged,
this, [](const QString& algorithmId, const QMap<QString, QVariant>& config) {
qDebug() << "Algorithm" << algorithmId << "reconfigured";
});QDiffX provides specialized support for side-by-side diffs:
auto sideBySideResult = manager->calculateSideBySideDiffSync(leftText, rightText);
if (sideBySideResult.success()) {
// Left side contains Equal + Delete operations
auto leftChanges = sideBySideResult.leftSide.changes();
// Right side contains Equal + Insert operations
auto rightChanges = sideBySideResult.rightSide.changes();
// Algorithm used for calculation
QString algorithm = sideBySideResult.algorithmUsed;
}Diff results include metadata for analysis:
auto result = manager->calculateDiffSync(leftText, rightText);
// Access metadata
auto metadata = result.allMetaData();
int executionTime = metadata["executionTime"].toInt();
QString algorithmUsed = metadata["algorithm"].toString();
int changeCount = metadata["changeCount"].toInt();git clone https://github.com/yourusername/QDiffX.git
cmake -S QDiffX -B build
cmake --build buildA demo application is included to test the widget and available algorithms.
Contributions are welcome and should be small and focused.
Key points:
- Unit tests are required for new algorithms and logic changes
- Tests run automatically in CI
- Builds and tests run on Linux, Windows, and macOS
- Failing tests block merges to protected branches
If you add:
- A new algorithm → include tests
- A bug fix → include a regression test
This keeps the core stable and predictable.
- Add More themes
- Direct editing
- Directory comparison
- Three-way merge
- Additional themes
- Smarter automatic algorithm selection
MIT License — see the LICENSE file for details.