// retoor #include "r_diff.h" #include #include #include #include #include #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); }