diff --git a/Makefile b/Makefile index a3942e0..4de4598 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ LIBS = -lm -lncurses SRC_DIR = src INC_DIR = include BUILD_DIR = build +TEST_DIR = tests # Get all .c files recursively from src directory and subdirectories SOURCES = $(shell find $(SRC_DIR) -name "*.c") @@ -13,6 +14,9 @@ SOURCES = $(shell find $(SRC_DIR) -name "*.c") OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) TARGET = shell +# Test targets +TEST_TIMER = $(TEST_DIR)/test_timer + all: $(BUILD_DIR) $(TARGET) $(BUILD_DIR): @@ -29,4 +33,18 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c clean: rm -rf $(BUILD_DIR) $(TARGET) -.PHONY: all clean +# Test targets +test: test_timer + +test_timer: $(TEST_TIMER) + @echo "\n--- Running timer tests ---" + @./$(TEST_TIMER) + +$(TEST_TIMER): $(TEST_DIR)/test_timer.c $(TEST_DIR)/timer_testable.c + @mkdir -p $(TEST_DIR) + $(CC) $(CFLAGS) $^ -o $@ + +clean_tests: + rm -f $(TEST_TIMER) + +.PHONY: all clean test test_timer clean_tests diff --git a/include/ui/ncurses_diff_viewer.h b/include/ui/ncurses_diff_viewer.h index 3b66528..95590f5 100644 --- a/include/ui/ncurses_diff_viewer.h +++ b/include/ui/ncurses_diff_viewer.h @@ -8,7 +8,7 @@ #define MAX_FILES 100 #define MAX_FILENAME_LEN 256 #define MAX_FULL_FILE_LINES 2000 -#define MAX_COMMITS 50 +#define MAX_COMMITS 1000 #define MAX_COMMIT_TITLE_LEN 256 #define MAX_AUTHOR_INITIALS 3 #define MAX_STASHES 100 @@ -92,8 +92,9 @@ typedef struct { int file_line_count; int file_scroll_offset; int file_cursor_line; - NCursesCommit commits[MAX_COMMITS]; + NCursesCommit *commits; int commit_count; + int commit_capacity; int selected_commit; int commit_scroll_offset; NCursesStash stashes[MAX_STASHES]; diff --git a/include/utils/timer.h b/include/utils/timer.h index 7b1225f..aa153cf 100644 --- a/include/utils/timer.h +++ b/include/utils/timer.h @@ -1,13 +1,10 @@ - #ifndef TIMER_H #define TIMER_H #include "common.h" void format_time(double ms, char *buffer, size_t buffer_size); - int lsh_timer(char **args); - int lsh_time(char **args); #endif // TIMER_H diff --git a/src/ui/ncurses_diff_viewer.c b/src/ui/ncurses_diff_viewer.c index 436e316..e9aca87 100644 --- a/src/ui/ncurses_diff_viewer.c +++ b/src/ui/ncurses_diff_viewer.c @@ -97,10 +97,15 @@ int init_ncurses_diff_viewer(NCursesDiffViewer *viewer) { memset(viewer, 0, sizeof(NCursesDiffViewer)); - // Initialize fuzzy search + viewer->commit_capacity = MAX_COMMITS; + viewer->commits = malloc(viewer->commit_capacity * sizeof(NCursesCommit)); + if (!viewer->commits) { + fprintf(stderr, "Failed to allocate memory for commits\n"); + return 0; + } + init_fuzzy_search(viewer); - // Initialize grep search init_grep_search(viewer); viewer->commit_scroll_offset = 0; @@ -308,7 +313,6 @@ int is_ncurses_new_file(const char *filename) { return !is_tracked; // Return 1 if not tracked (new file) } - int load_file_with_staging_info(NCursesDiffViewer *viewer, const char *filename) { if (!viewer || !filename) @@ -459,7 +463,6 @@ int load_file_with_staging_info(NCursesDiffViewer *viewer, return viewer->file_line_count; } - // this is a change // this is another change int stage_hunk_by_line(NCursesDiffViewer *viewer, int line_index) { @@ -760,7 +763,6 @@ void rebuild_staged_view_from_git(NCursesDiffViewer *viewer) { pclose(diff_fp); } - int apply_staged_changes(NCursesDiffViewer *viewer) { if (!viewer || viewer->staged_line_count == 0) return 0; @@ -807,7 +809,6 @@ int apply_staged_changes(NCursesDiffViewer *viewer) { return (result == 0); } - int unstage_line_from_git(NCursesDiffViewer *viewer, int staged_line_index) { if (!viewer || staged_line_index < 0 || staged_line_index >= viewer->staged_line_count) @@ -844,7 +845,6 @@ int unstage_line_from_git(NCursesDiffViewer *viewer, int staged_line_index) { return 0; } - int reset_staged_changes(NCursesDiffViewer *viewer) { if (!viewer) return 0; @@ -889,8 +889,7 @@ int get_commit_history(NCursesDiffViewer *viewer) { if (!viewer) return 0; - FILE *fp = - popen("git log --oneline -20 --format=\"%h|%an|%s\" 2>/dev/null", "r"); + FILE *fp = popen("git log --oneline --format=\"%h|%an|%s\" 2>/dev/null", "r"); if (!fp) return 0; @@ -898,14 +897,19 @@ int get_commit_history(NCursesDiffViewer *viewer) { char line[512]; // Get list of unpushed commits first - char unpushed_hashes[MAX_COMMITS][16]; + char **unpushed_hashes = malloc(1000 * sizeof(char *)); int unpushed_count = 0; + int unpushed_capacity = 1000; + + for (int i = 0; i < unpushed_capacity; i++) { + unpushed_hashes[i] = malloc(16); + } FILE *unpushed_fp = popen("git log origin/HEAD..HEAD --format=\"%h\" 2>/dev/null", "r"); if (unpushed_fp) { while (fgets(line, sizeof(line), unpushed_fp) != NULL && - unpushed_count < MAX_COMMITS) { + unpushed_count < unpushed_capacity) { char *newline = strchr(line, '\n'); if (newline) *newline = '\0'; @@ -924,7 +928,7 @@ int get_commit_history(NCursesDiffViewer *viewer) { popen("git log origin/main..HEAD --format=\"%h\" 2>/dev/null", "r"); if (unpushed_fp) { while (fgets(line, sizeof(line), unpushed_fp) != NULL && - unpushed_count < MAX_COMMITS) { + unpushed_count < unpushed_capacity) { char *newline = strchr(line, '\n'); if (newline) *newline = '\0'; @@ -943,7 +947,7 @@ int get_commit_history(NCursesDiffViewer *viewer) { popen("git log origin/master..HEAD --format=\"%h\" 2>/dev/null", "r"); if (unpushed_fp) { while (fgets(line, sizeof(line), unpushed_fp) != NULL && - unpushed_count < MAX_COMMITS) { + unpushed_count < unpushed_capacity) { char *newline = strchr(line, '\n'); if (newline) *newline = '\0'; @@ -957,8 +961,17 @@ int get_commit_history(NCursesDiffViewer *viewer) { } } - while (fgets(line, sizeof(line), fp) != NULL && - viewer->commit_count < MAX_COMMITS) { + while (fgets(line, sizeof(line), fp) != NULL) { + if (viewer->commit_count >= viewer->commit_capacity) { + viewer->commit_capacity *= 2; + NCursesCommit *new_commits = realloc( + viewer->commits, viewer->commit_capacity * sizeof(NCursesCommit)); + if (!new_commits) { + fprintf(stderr, "Failed to reallocate commits array\n"); + break; + } + viewer->commits = new_commits; + } // Remove newline char *newline = strchr(line, '\n'); if (newline) @@ -1004,6 +1017,12 @@ int get_commit_history(NCursesDiffViewer *viewer) { } pclose(fp); + + for (int i = 0; i < unpushed_capacity; i++) { + free(unpushed_hashes[i]); + } + free(unpushed_hashes); + return viewer->commit_count; } @@ -1190,7 +1209,6 @@ int show_reset_confirmation_dialog(void) { return 0; } - int get_commit_title_input(char *title, int max_len, char *message, int max_message_len) { if (!title) @@ -2527,7 +2545,6 @@ void render_file_list_window(NCursesDiffViewer *viewer) { wrefresh(viewer->file_list_win); } - void render_commit_list_window(NCursesDiffViewer *viewer) { if (!viewer || !viewer->commit_list_win) return; @@ -2535,9 +2552,15 @@ void render_commit_list_window(NCursesDiffViewer *viewer) { // CRITICAL: Clear the entire window first werase(viewer->commit_list_win); - // Draw rounded border and title draw_rounded_box(viewer->commit_list_win); - mvwprintw(viewer->commit_list_win, 0, 2, " 4. Commits "); + char commit_title[64]; + if (viewer->commit_count > 0) { + snprintf(commit_title, sizeof(commit_title), " 4. Commits (%d/%d) ", + viewer->selected_commit + 1, viewer->commit_count); + } else { + snprintf(commit_title, sizeof(commit_title), " 4. Commits (0) "); + } + mvwprintw(viewer->commit_list_win, 0, 2, "%s", commit_title); int max_commits_visible = viewer->commit_panel_height - 2; @@ -4777,8 +4800,6 @@ int run_ncurses_diff_viewer(void) { return 0; } - - int get_ncurses_git_branches(NCursesDiffViewer *viewer) { if (!viewer) return 0; @@ -5654,9 +5675,15 @@ void render_stash_list_window(NCursesDiffViewer *viewer) { // Clear the entire window first werase(viewer->stash_list_win); - // Draw rounded border and title draw_rounded_box(viewer->stash_list_win); - mvwprintw(viewer->stash_list_win, 0, 2, " 5. Stashes "); + char stash_title[64]; + if (viewer->stash_count > 0) { + snprintf(stash_title, sizeof(stash_title), " 5. Stashes (%d/%d) ", + viewer->selected_stash + 1, viewer->stash_count); + } else { + snprintf(stash_title, sizeof(stash_title), " 5. Stashes (0) "); + } + mvwprintw(viewer->stash_list_win, 0, 2, "%s", stash_title); int max_stashes_visible = viewer->stash_panel_height - 2; @@ -5804,7 +5831,14 @@ void render_branch_list_window(NCursesDiffViewer *viewer) { werase(viewer->branch_list_win); draw_rounded_box(viewer->branch_list_win); - mvwprintw(viewer->branch_list_win, 0, 2, " 3. Branches "); + char branch_title[64]; + if (viewer->branch_count > 0) { + snprintf(branch_title, sizeof(branch_title), " 3. Branches (%d/%d) ", + viewer->selected_branch + 1, viewer->branch_count); + } else { + snprintf(branch_title, sizeof(branch_title), " 3. Branches (0) "); + } + mvwprintw(viewer->branch_list_win, 0, 2, "%s", branch_title); int max_branches_visible = viewer->branch_panel_height - 2; @@ -6809,9 +6843,13 @@ void cleanup_ncurses_diff_viewer(NCursesDiffViewer *viewer) { delwin(viewer->status_bar_win); } - // Clean up fuzzy search windows cleanup_fuzzy_search(viewer); + if (viewer->commits) { + free(viewer->commits); + viewer->commits = NULL; + } + // Clean up grep search windows cleanup_grep_search(viewer); } diff --git a/src/utils/timer.c b/src/utils/timer.c index 97c5d71..51d7269 100644 --- a/src/utils/timer.c +++ b/src/utils/timer.c @@ -1,21 +1,16 @@ - +#include "utils/timer.h" #include "builtins.h" -#include "common.h" #include "shell.h" #include void format_time(double ms, char *buffer, size_t buffer_size) { if (ms < 1.0) { - // Microseconds snprintf(buffer, buffer_size, "%.2f μs", ms * 1000); } else if (ms < 1000.0) { - // Milliseconds snprintf(buffer, buffer_size, "%.2f ms", ms); } else if (ms < 60000.0) { - // Seconds snprintf(buffer, buffer_size, "%.2f s", ms / 1000); } else { - // Minutes and seconds int minutes = (int)(ms / 60000); double seconds = (ms - minutes * 60000) / 1000; snprintf(buffer, buffer_size, "%d min %.2f s", minutes, seconds); @@ -24,49 +19,35 @@ void format_time(double ms, char *buffer, size_t buffer_size) { int lsh_timer(char **args) { if (!args[1]) { - printf("timer: usage: timer COMMAND [ARGS...]\n"); - printf("Measures execution time of a command\n"); + fprintf(stderr, "timer: usage: timer COMMAND [ARGS...]\n"); return 1; } - // Create a new array for the command to execute (without "timer" prefix) char **cmd_args = &args[1]; - // Start timing - clock_t start_time = clock(); - - // Execute the command - int result; + // Don't time commands that affect shell state if (strcmp(cmd_args[0], "cd") == 0 || strcmp(cmd_args[0], "exit") == 0 || strcmp(cmd_args[0], "timer") == 0) { - // Handle built-in commands that might affect shell state - printf("timer: can't time built-in command: %s\n", cmd_args[0]); - result = 1; - } else { - // Execute the command normally - result = lsh_execute(cmd_args); + fprintf(stderr, "timer: can't time built-in command: %s\n", cmd_args[0]); + return 1; } - // End timing - clock_t end_time = clock(); + clock_t start = clock(); + int result = lsh_execute(cmd_args); + clock_t end = clock(); - // Calculate execution time in milliseconds - double execution_time_ms = - ((double)(end_time - start_time) / CLOCKS_PER_SEC) * 1000; + double ms = ((double)(end - start) / CLOCKS_PER_SEC) * 1000; - // Format the execution time char time_str[64]; - format_time(execution_time_ms, time_str, sizeof(time_str)); + format_time(ms, time_str, sizeof(time_str)); - // Print the execution time with color - printf("\n"); - printf(ANSI_COLOR_GREEN); // Green text for highlighted display - printf("╭───────────────────────────────╮\n"); - printf("│ Execution time: %-14s │\n", time_str); - printf("╰───────────────────────────────╯\n"); - printf(ANSI_COLOR_RESET); // Reset color + printf("\n" ANSI_COLOR_GREEN); + printf("╭───────────────────────────────────╮\n"); + printf("│ Execution time: %-18s │\n", time_str); + printf("╰───────────────────────────────────╯\n"); + printf(ANSI_COLOR_RESET); return result; } -int lsh_time(char **args) { return lsh_timer(args); } \ No newline at end of file +int lsh_time(char **args) { return lsh_timer(args); }