file comparison improved
This commit is contained in:
parent
b1b10769e2
commit
f4cb0c4b1f
@ -20,6 +20,8 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
private final AppConfig config;
|
private final AppConfig config;
|
||||||
private JTextPane textPane1;
|
private JTextPane textPane1;
|
||||||
private JTextPane textPane2;
|
private JTextPane textPane2;
|
||||||
|
private JTextArea lineNumbers1;
|
||||||
|
private JTextArea lineNumbers2;
|
||||||
private JScrollPane scroll1;
|
private JScrollPane scroll1;
|
||||||
private JScrollPane scroll2;
|
private JScrollPane scroll2;
|
||||||
private List<String> lines1 = new ArrayList<>();
|
private List<String> lines1 = new ArrayList<>();
|
||||||
@ -34,6 +36,7 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
try {
|
try {
|
||||||
this.lines1 = readLines(file1);
|
this.lines1 = readLines(file1);
|
||||||
this.lines2 = readLines(file2);
|
this.lines2 = readLines(file2);
|
||||||
|
performSmartAlignment();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
JOptionPane.showMessageDialog(this, "Error reading files: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Error reading files: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
@ -67,6 +70,14 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
textPane1.addMouseListener(listener1);
|
textPane1.addMouseListener(listener1);
|
||||||
scroll1 = new JScrollPane(textPane1);
|
scroll1 = new JScrollPane(textPane1);
|
||||||
|
|
||||||
|
lineNumbers1 = new JTextArea("1");
|
||||||
|
lineNumbers1.setEditable(false);
|
||||||
|
lineNumbers1.setBackground(Color.LIGHT_GRAY);
|
||||||
|
lineNumbers1.setForeground(Color.DARK_GRAY);
|
||||||
|
lineNumbers1.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||||
|
lineNumbers1.setMargin(new Insets(0, 5, 0, 5));
|
||||||
|
scroll1.setRowHeaderView(lineNumbers1);
|
||||||
|
|
||||||
textPane2 = new JTextPane();
|
textPane2 = new JTextPane();
|
||||||
textPane2.setEditable(false);
|
textPane2.setEditable(false);
|
||||||
textPane2.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
textPane2.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||||
@ -74,6 +85,14 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
textPane2.addMouseListener(listener2);
|
textPane2.addMouseListener(listener2);
|
||||||
scroll2 = new JScrollPane(textPane2);
|
scroll2 = new JScrollPane(textPane2);
|
||||||
|
|
||||||
|
lineNumbers2 = new JTextArea("1");
|
||||||
|
lineNumbers2.setEditable(false);
|
||||||
|
lineNumbers2.setBackground(Color.LIGHT_GRAY);
|
||||||
|
lineNumbers2.setForeground(Color.DARK_GRAY);
|
||||||
|
lineNumbers2.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||||
|
lineNumbers2.setMargin(new Insets(0, 5, 0, 5));
|
||||||
|
scroll2.setRowHeaderView(lineNumbers2);
|
||||||
|
|
||||||
// Synchronize scrolling
|
// Synchronize scrolling
|
||||||
scroll1.getVerticalScrollBar().setModel(scroll2.getVerticalScrollBar().getModel());
|
scroll1.getVerticalScrollBar().setModel(scroll2.getVerticalScrollBar().getModel());
|
||||||
|
|
||||||
@ -153,12 +172,12 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
if (line1 < line2) {
|
if (line1 < line2) {
|
||||||
int diff = line2 - line1;
|
int diff = line2 - line1;
|
||||||
for (int i = 0; i < diff; i++) {
|
for (int i = 0; i < diff; i++) {
|
||||||
lines1.add(line1, "");
|
lines1.add(line1, null);
|
||||||
}
|
}
|
||||||
} else if (line2 < line1) {
|
} else if (line2 < line1) {
|
||||||
int diff = line1 - line2;
|
int diff = line1 - line2;
|
||||||
for (int i = 0; i < diff; i++) {
|
for (int i = 0; i < diff; i++) {
|
||||||
lines2.add(line2, "");
|
lines2.add(line2, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateDisplay(false);
|
updateDisplay(false);
|
||||||
@ -198,6 +217,15 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
textPane2.setForeground(dark ? Color.WHITE : Color.BLACK);
|
textPane2.setForeground(dark ? Color.WHITE : Color.BLACK);
|
||||||
textPane1.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
textPane1.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
||||||
textPane2.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
textPane2.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
||||||
|
|
||||||
|
if (lineNumbers1 != null) {
|
||||||
|
lineNumbers1.setBackground(dark ? bg.brighter() : bg.darker());
|
||||||
|
lineNumbers1.setForeground(dark ? Color.LIGHT_GRAY : Color.DARK_GRAY);
|
||||||
|
}
|
||||||
|
if (lineNumbers2 != null) {
|
||||||
|
lineNumbers2.setBackground(dark ? bg.brighter() : bg.darker());
|
||||||
|
lineNumbers2.setForeground(dark ? Color.LIGHT_GRAY : Color.DARK_GRAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Font f = config.getGlobalFont();
|
Font f = config.getGlobalFont();
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
@ -205,6 +233,8 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
Font mono = new Font("Monospaced", Font.PLAIN, f.getSize());
|
Font mono = new Font("Monospaced", Font.PLAIN, f.getSize());
|
||||||
textPane1.setFont(mono);
|
textPane1.setFont(mono);
|
||||||
textPane2.setFont(mono);
|
textPane2.setFont(mono);
|
||||||
|
if (lineNumbers1 != null) lineNumbers1.setFont(mono);
|
||||||
|
if (lineNumbers2 != null) lineNumbers2.setFont(mono);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,6 +252,8 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
textPane2.setText("");
|
textPane2.setText("");
|
||||||
StyledDocument doc1 = textPane1.getStyledDocument();
|
StyledDocument doc1 = textPane1.getStyledDocument();
|
||||||
StyledDocument doc2 = textPane2.getStyledDocument();
|
StyledDocument doc2 = textPane2.getStyledDocument();
|
||||||
|
StringBuilder ln1 = new StringBuilder();
|
||||||
|
StringBuilder ln2 = new StringBuilder();
|
||||||
|
|
||||||
Style diffStyle = textPane1.addStyle("diff", null);
|
Style diffStyle = textPane1.addStyle("diff", null);
|
||||||
Color bg = textPane1.getBackground();
|
Color bg = textPane1.getBackground();
|
||||||
@ -230,17 +262,36 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
StyleConstants.setForeground(diffStyle, dark ? Color.WHITE : Color.BLACK);
|
StyleConstants.setForeground(diffStyle, dark ? Color.WHITE : Color.BLACK);
|
||||||
|
|
||||||
int maxLines = Math.max(lines1.size(), lines2.size());
|
int maxLines = Math.max(lines1.size(), lines2.size());
|
||||||
for (int i = 0; i < maxLines; i++) {
|
int counter1 = 1;
|
||||||
String l1 = i < lines1.size() ? lines1.get(i) : "";
|
int counter2 = 1;
|
||||||
String l2 = i < lines2.size() ? lines2.get(i) : "";
|
|
||||||
|
|
||||||
boolean different = !l1.equals(l2);
|
for (int i = 0; i < maxLines; i++) {
|
||||||
|
String l1 = i < lines1.size() ? lines1.get(i) : null;
|
||||||
|
String l2 = i < lines2.size() ? lines2.get(i) : null;
|
||||||
|
|
||||||
|
boolean different = (l1 == null && l2 != null) || (l1 != null && l2 == null) || (l1 != null && l2 != null && !l1.equals(l2));
|
||||||
Style s = different ? diffStyle : null;
|
Style s = different ? diffStyle : null;
|
||||||
|
|
||||||
|
if (l1 != null) {
|
||||||
doc1.insertString(doc1.getLength(), l1 + "\n", s);
|
doc1.insertString(doc1.getLength(), l1 + "\n", s);
|
||||||
doc2.insertString(doc2.getLength(), l2 + "\n", s);
|
ln1.append(counter1++).append("\n");
|
||||||
|
} else {
|
||||||
|
doc1.insertString(doc1.getLength(), "\n", s);
|
||||||
|
ln1.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (l2 != null) {
|
||||||
|
doc2.insertString(doc2.getLength(), l2 + "\n", s);
|
||||||
|
ln2.append(counter2++).append("\n");
|
||||||
|
} else {
|
||||||
|
doc2.insertString(doc2.getLength(), "\n", s);
|
||||||
|
ln2.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineNumbers1 != null) lineNumbers1.setText(ln1.toString());
|
||||||
|
if (lineNumbers2 != null) lineNumbers2.setText(ln2.toString());
|
||||||
|
|
||||||
if (resetCaret) {
|
if (resetCaret) {
|
||||||
textPane1.setCaretPosition(0);
|
textPane1.setCaretPosition(0);
|
||||||
textPane2.setCaretPosition(0);
|
textPane2.setCaretPosition(0);
|
||||||
@ -250,6 +301,60 @@ public class FileComparisonDialog extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void performSmartAlignment() {
|
||||||
|
if (lines1.isEmpty() || lines2.isEmpty()) return;
|
||||||
|
|
||||||
|
// Skip alignment for very large files to avoid O(N^2) memory/time issues
|
||||||
|
if (lines1.size() > 2000 || lines2.size() > 2000) return;
|
||||||
|
|
||||||
|
int n = lines1.size();
|
||||||
|
int m = lines2.size();
|
||||||
|
int[][] dp = new int[n + 1][m + 1];
|
||||||
|
|
||||||
|
// LCS computation with similarity check (exact or trimmed match)
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
for (int j = 1; j <= m; j++) {
|
||||||
|
String s1 = lines1.get(i - 1);
|
||||||
|
String s2 = lines2.get(j - 1);
|
||||||
|
if (s1.equals(s2) || (!s1.trim().isEmpty() && s1.trim().equals(s2.trim()))) {
|
||||||
|
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||||
|
} else {
|
||||||
|
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> aligned1 = new ArrayList<>();
|
||||||
|
List<String> aligned2 = new ArrayList<>();
|
||||||
|
int i = n, j = m;
|
||||||
|
while (i > 0 || j > 0) {
|
||||||
|
if (i > 0 && j > 0) {
|
||||||
|
String s1 = lines1.get(i - 1);
|
||||||
|
String s2 = lines2.get(j - 1);
|
||||||
|
if (s1.equals(s2) || (!s1.trim().isEmpty() && s1.trim().equals(s2.trim()))) {
|
||||||
|
aligned1.add(0, s1);
|
||||||
|
aligned2.add(0, s2);
|
||||||
|
i--;
|
||||||
|
j--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j > 0 && (i == 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
||||||
|
aligned1.add(0, null); // Added gap marker
|
||||||
|
aligned2.add(0, lines2.get(j - 1));
|
||||||
|
j--;
|
||||||
|
} else if (i > 0) {
|
||||||
|
aligned1.add(0, lines1.get(i - 1));
|
||||||
|
aligned2.add(0, null); // Added gap marker
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lines1 = aligned1;
|
||||||
|
this.lines2 = aligned2;
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> readLines(File f) throws IOException {
|
private List<String> readLines(File f) throws IOException {
|
||||||
List<String> lines = new ArrayList<>();
|
List<String> lines = new ArrayList<>();
|
||||||
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
|
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user