|
// retoor <retoor@molodetz.nl>
|
|
|
|
#include "r_diff.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
#define COLOR_RED "\x1b[31m"
|
|
#define COLOR_GREEN "\x1b[32m"
|
|
#define COLOR_CYAN "\x1b[36m"
|
|
#define COLOR_RESET "\x1b[0m"
|
|
#define COLOR_DIM "\x1b[2m"
|
|
#define COLOR_BG_RED "\x1b[41;37m"
|
|
#define COLOR_BG_GREEN "\x1b[42;30m"
|
|
|
|
typedef struct {
|
|
char **lines;
|
|
size_t count;
|
|
} line_set_t;
|
|
|
|
static line_set_t split_lines(const char *str) {
|
|
line_set_t set = {NULL, 0};
|
|
if (!str || !*str) return set;
|
|
|
|
char *copy = strdup(str);
|
|
char *p = copy;
|
|
char *line_start = copy;
|
|
|
|
while (*p) {
|
|
if (*p == '\n') {
|
|
*p = '\0';
|
|
set.lines = realloc(set.lines, sizeof(char *) * (set.count + 1));
|
|
set.lines[set.count++] = strdup(line_start);
|
|
line_start = p + 1;
|
|
}
|
|
p++;
|
|
}
|
|
// Handle last line if no trailing newline
|
|
if (*line_start) {
|
|
set.lines = realloc(set.lines, sizeof(char *) * (set.count + 1));
|
|
set.lines[set.count++] = strdup(line_start);
|
|
}
|
|
|
|
free(copy);
|
|
return set;
|
|
}
|
|
|
|
static void free_line_set(line_set_t set) {
|
|
for (size_t i = 0; i < set.count; i++) free(set.lines[i]);
|
|
free(set.lines);
|
|
}
|
|
|
|
static void print_truncated(const char *str, int width, const char *color) {
|
|
if (width <= 0) return;
|
|
int len = (int)strlen(str);
|
|
if (color) printf("%s", color);
|
|
|
|
if (len > width && width > 3) {
|
|
char *temp = strndup(str, (size_t)width - 3);
|
|
printf("%s...", temp);
|
|
free(temp);
|
|
} else {
|
|
printf("%-*.*s", width, width, str);
|
|
}
|
|
|
|
if (color) printf("%s", COLOR_RESET);
|
|
}
|
|
|
|
void r_diff_print(const char *path, const char *old_content, const char *new_content) {
|
|
line_set_t old_set = split_lines(old_content);
|
|
line_set_t new_set = split_lines(new_content);
|
|
|
|
struct winsize w;
|
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
|
int term_width = w.ws_col > 0 ? w.ws_col : 120;
|
|
if (term_width < 40) term_width = 40; // Minimum usable width
|
|
int col_width = (term_width - 15) / 2;
|
|
if (col_width < 5) col_width = 5;
|
|
|
|
printf("\n%s %s CHANGES: %s %s\n", COLOR_CYAN, COLOR_DIM, path, COLOR_RESET);
|
|
printf("%4s %-*s | %4s %-*s\n", "LINE", col_width, " OLD", "LINE", col_width, " NEW");
|
|
printf("%.*s\n", term_width, "--------------------------------------------------------------------------------------------------------------------------------------------");
|
|
|
|
size_t o = 0, n = 0;
|
|
while (o < old_set.count || n < new_set.count) {
|
|
bool match = false;
|
|
if (o < old_set.count && n < new_set.count) {
|
|
if (strcmp(old_set.lines[o], new_set.lines[n]) == 0) {
|
|
printf("%4zu ", o + 1);
|
|
print_truncated(old_set.lines[o], col_width - 2, NULL);
|
|
printf(" | %4zu ", n + 1);
|
|
print_truncated(new_set.lines[n], col_width - 2, NULL);
|
|
printf("\n");
|
|
o++; n++;
|
|
match = true;
|
|
}
|
|
}
|
|
|
|
if (!match) {
|
|
bool found_o_later = false;
|
|
if (o < old_set.count) {
|
|
for (size_t i = n + 1; i < new_set.count && i < n + 5; i++) {
|
|
if (strcmp(old_set.lines[o], new_set.lines[i]) == 0) {
|
|
found_o_later = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found_o_later) {
|
|
// Line added on NEW side
|
|
printf("%4s ", "");
|
|
print_truncated("", col_width - 2, NULL);
|
|
printf(" | %4zu %s+%s ", n + 1, COLOR_GREEN, COLOR_RESET);
|
|
print_truncated(new_set.lines[n], col_width - 2, COLOR_GREEN);
|
|
printf("\n");
|
|
n++;
|
|
} else if (o < old_set.count) {
|
|
// Line removed on OLD side
|
|
printf("%4zu %s-%s ", o + 1, COLOR_RED, COLOR_RESET);
|
|
print_truncated(old_set.lines[o], col_width - 2, COLOR_RED);
|
|
printf(" | %4s ", "");
|
|
print_truncated("", col_width - 2, NULL);
|
|
printf("\n");
|
|
o++;
|
|
} else if (n < new_set.count) {
|
|
// Line added on NEW side
|
|
printf("%4s ", "");
|
|
print_truncated("", col_width - 2, NULL);
|
|
printf(" | %4zu %s+%s ", n + 1, COLOR_GREEN, COLOR_RESET);
|
|
print_truncated(new_set.lines[n], col_width - 2, COLOR_GREEN);
|
|
printf("\n");
|
|
n++;
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
usleep(30000); // 30ms delay for streaming effect
|
|
}
|
|
printf("\n");
|
|
fflush(stdout);
|
|
|
|
free_line_set(old_set);
|
|
free_line_set(new_set);
|
|
} |