diff --git a/src/cnfind.c b/src/cnfind.c index 322ba30..0aa0751 100644 --- a/src/cnfind.c +++ b/src/cnfind.c @@ -9,10 +9,29 @@ #include "platform.h" #include "config.h" +/* Terminal width detection */ +#if defined(__MSDOS__) || defined(__DOS__) + /* DOS: assume 80 columns */ +#elif defined(_WIN32) + #include +#else + #include + #include +#endif + #define MAX_LENGTH 500 #define DATE_LENGTH 10 #define TIME_LENGTH 5 #define TXTMSG_LENGTH 125 +#define DEFAULT_TERM_WIDTH 80 +#define MIN_TEXT_WIDTH 20 + +/* Fixed column widths (ln + date + time + category + separators) */ +#define FIXED_COLS (5 + DATE_LENGTH + TIME_LENGTH + CATEGORY_LENGTH + 20) + +/* Output settings */ +static int g_simple_mode = 0; +static int g_text_width = TXTMSG_LENGTH; typedef struct { char date[DATE_LENGTH + 1]; @@ -22,6 +41,37 @@ typedef struct { int line_num; } Entry; +/* Get terminal width */ +static int get_terminal_width(void) { +#if defined(__MSDOS__) || defined(__DOS__) + return 80; +#elif defined(_WIN32) + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { + return csbi.srWindow.Right - csbi.srWindow.Left + 1; + } + return DEFAULT_TERM_WIDTH; +#else + struct winsize ws; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) { + return ws.ws_col; + } + return DEFAULT_TERM_WIDTH; +#endif +} + +/* Calculate text column width based on terminal size */ +static int calc_text_width(int term_width) { + int available = term_width - FIXED_COLS; + if (available < MIN_TEXT_WIDTH) { + available = MIN_TEXT_WIDTH; + } + if (available > TXTMSG_LENGTH) { + available = TXTMSG_LENGTH; + } + return available; +} + /* Case-insensitive substring search */ static char *stristr(const char *haystack, const char *needle) { const char *h; @@ -147,33 +197,76 @@ void print_horizontal_line(char left, char middle, char right, char fill) { for (i = 0; i < CATEGORY_LENGTH + 2; i++) printf("%c", fill); printf("%c", middle); - /* Free text column */ - for (i = 0; i < TXTMSG_LENGTH + 2; i++) printf("%c", fill); + /* Free text column (dynamic width) */ + for (i = 0; i < g_text_width + 2; i++) printf("%c", fill); printf("%c\n", right); } +void print_simple_separator(void) { + int i; + int total_width = 5 + DATE_LENGTH + TIME_LENGTH + CATEGORY_LENGTH + g_text_width + 12; + for (i = 0; i < total_width; i++) printf("-"); + printf("\n"); +} + void print_header(int is_archive) { - print_horizontal_line('+', '+', '+', '='); - printf("| %-3s | %-*s | %-*s | %-*s | %-*s |\n", - "Ln", - DATE_LENGTH, "Date", - TIME_LENGTH, "Time", - CATEGORY_LENGTH, "Category", - TXTMSG_LENGTH, is_archive ? "Free Text (ARCHIVED)" : "Free Text"); - print_horizontal_line('+', '+', '+', '='); + const char *text_label = is_archive ? "Free Text (ARCHIVED)" : "Free Text"; + + if (g_simple_mode) { + printf("%-3s %-*s %-*s %-*s %s\n", + "Ln", + DATE_LENGTH, "Date", + TIME_LENGTH, "Time", + CATEGORY_LENGTH, "Category", + text_label); + print_simple_separator(); + } else { + print_horizontal_line('+', '+', '+', '='); + printf("| %-3s | %-*s | %-*s | %-*s | %-*s |\n", + "Ln", + DATE_LENGTH, "Date", + TIME_LENGTH, "Time", + CATEGORY_LENGTH, "Category", + g_text_width, text_label); + print_horizontal_line('+', '+', '+', '='); + } } void print_footer(void) { - print_horizontal_line('+', '+', '+', '-'); + if (!g_simple_mode) { + print_horizontal_line('+', '+', '+', '-'); + } } void print_entry(const Entry *entry) { - printf("| %3d | %-*s | %-*s | %-*s | %-*s |\n", - entry->line_num, - DATE_LENGTH, entry->date, - TIME_LENGTH, entry->time, - CATEGORY_LENGTH, entry->category, - TXTMSG_LENGTH, entry->text); + char truncated_text[TXTMSG_LENGTH + 1]; + int text_len; + + /* Truncate text if needed */ + text_len = (int)strlen(entry->text); + if (text_len > g_text_width) { + strncpy(truncated_text, entry->text, g_text_width - 3); + truncated_text[g_text_width - 3] = '\0'; + strcat(truncated_text, "..."); + } else { + strcpy(truncated_text, entry->text); + } + + if (g_simple_mode) { + printf("%3d %-*s %-*s %-*s %s\n", + entry->line_num, + DATE_LENGTH, entry->date, + TIME_LENGTH, entry->time, + CATEGORY_LENGTH, entry->category, + truncated_text); + } else { + printf("| %3d | %-*s | %-*s | %-*s | %-*s |\n", + entry->line_num, + DATE_LENGTH, entry->date, + TIME_LENGTH, entry->time, + CATEGORY_LENGTH, entry->category, + g_text_width, truncated_text); + } } void print_usage(const char *prog_name) { @@ -186,6 +279,7 @@ void print_usage(const char *prog_name) { fprintf(stderr, " -d DATE Filter by date (YYYY-MM-DD)\n"); fprintf(stderr, " -i Case-sensitive search (default is case-insensitive)\n"); fprintf(stderr, " -n Show only count of matches\n"); + fprintf(stderr, " -s, --simple Simple output (no box borders)\n"); fprintf(stderr, " -a, --archive Search archived entries instead of active\n"); fprintf(stderr, " -h, --help Show this help message\n"); fprintf(stderr, "\n"); @@ -244,6 +338,9 @@ int main(int argc, char *argv[]) { else if (strcmp(argv[i], "-n") == 0) { count_only = 1; } + else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--simple") == 0) { + g_simple_mode = 1; + } else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--archive") == 0) { search_archive = 1; } @@ -277,7 +374,7 @@ int main(int argc, char *argv[]) { return 1; } - notesfile = fopen(file_path, "r"); +notesfile = fopen(file_path, "r"); if (notesfile == NULL) { if (search_archive) { fprintf(stderr, "No archived entries found.\n"); @@ -288,6 +385,9 @@ int main(int argc, char *argv[]) { return 1; } + /* Calculate dynamic text width based on terminal */ + g_text_width = calc_text_width(get_terminal_width()); + /* Search entries */ while (fgets(line, MAX_LENGTH, notesfile) != NULL) { int matches = 1; diff --git a/src/cnhelp.c b/src/cnhelp.c index 8bc1b0e..231e95c 100644 --- a/src/cnhelp.c +++ b/src/cnhelp.c @@ -56,18 +56,21 @@ void print_cndump(void) { void print_cnfind(void) { printf("cnfind - Search notes by text, category, or date\n"); printf("\n"); - printf("Usage: cnfind [-c CAT] [-d DATE] [-i] [-n] [-a] [PATTERN]\n"); + printf("Usage: cnfind [-c CAT] [-d DATE] [-i] [-n] [-s] [-a] [PATTERN]\n"); printf("\n"); printf("Options:\n"); printf(" -c CATEGORY Filter by category\n"); printf(" -d DATE Filter by date (YYYY-MM-DD)\n"); printf(" -i Case-sensitive search\n"); printf(" -n Show only match count\n"); + printf(" -s, --simple Simple output (no box borders)\n"); printf(" -a, --archive Search archived entries\n"); printf("\n"); + printf("Output adapts to terminal width automatically.\n"); + printf("\n"); printf("Examples:\n"); printf(" cnfind meeting Search for 'meeting'\n"); - printf(" cnfind -c Work Show Work category\n"); + printf(" cnfind -s -c Work Show Work category (simple)\n"); printf(" cnfind -a meeting Search archive\n"); }