/** * ncurses_diff_viewer.h * NCurses-based interactive diff viewer for git changes */ #ifndef NCURSES_DIFF_VIEWER_H #define NCURSES_DIFF_VIEWER_H #include "common.h" #include #define MAX_FILES 100 #define MAX_FILENAME_LEN 256 #define MAX_FULL_FILE_LINES 2000 #define MAX_COMMITS 50 #define MAX_COMMIT_TITLE_LEN 256 #define MAX_AUTHOR_INITIALS 3 #define MAX_STASHES 20 #define MAX_BRANCHES 5 #define MAX_BRANCHNAME_LEN 256 typedef struct { char stash_info[512]; } NCursesStash; typedef struct { char filename[MAX_FILENAME_LEN]; char status; // 'M' = modified, 'A' = added, 'D' = deleted int marked_for_commit; // 1 if marked for commit, 0 otherwise } NCursesChangedFile; typedef struct { char name[MAX_BRANCHNAME_LEN]; int status; int commits_ahead; int commits_behind; } NCursesBranches; typedef struct { char line[1024]; char type; // '+' = addition, '-' = deletion, ' ' = context, '@' = hunk header int is_diff_line; // 1 if this is a diff line, 0 if original file line } NCursesFileLine; typedef struct { char hash[16]; // Short commit hash char author_initials[MAX_AUTHOR_INITIALS]; char title[MAX_COMMIT_TITLE_LEN]; int is_pushed; // 1 if pushed to remote, 0 if local only } NCursesCommit; typedef enum { NCURSES_MODE_FILE_LIST, NCURSES_MODE_FILE_VIEW, NCURSES_MODE_COMMIT_LIST, NCURSES_MODE_COMMIT_VIEW, NCURSES_MODE_STASH_LIST, NCURSES_MODE_STASH_VIEW, NCURSES_MODE_BRANCH_VIEW, NCURSES_MODE_BRANCH_LIST } NCursesViewMode; typedef enum { SYNC_STATUS_IDLE, SYNC_STATUS_SYNCING_APPEARING, SYNC_STATUS_SYNCING_VISIBLE, SYNC_STATUS_SYNCING_DISAPPEARING, SYNC_STATUS_PUSHING_APPEARING, SYNC_STATUS_PUSHING_VISIBLE, SYNC_STATUS_PUSHING_DISAPPEARING, SYNC_STATUS_PULLING_APPEARING, SYNC_STATUS_PULLING_VISIBLE, SYNC_STATUS_PULLING_DISAPPEARING, SYNC_STATUS_SYNCED_APPEARING, SYNC_STATUS_SYNCED_VISIBLE, SYNC_STATUS_SYNCED_DISAPPEARING, SYNC_STATUS_PUSHED_APPEARING, SYNC_STATUS_PUSHED_VISIBLE, SYNC_STATUS_PUSHED_DISAPPEARING, SYNC_STATUS_PULLED_APPEARING, SYNC_STATUS_PULLED_VISIBLE, SYNC_STATUS_PULLED_DISAPPEARING } SyncStatus; typedef struct { NCursesChangedFile files[MAX_FILES]; int file_count; int selected_file; NCursesFileLine file_lines[MAX_FULL_FILE_LINES]; int file_line_count; int file_scroll_offset; int file_cursor_line; NCursesCommit commits[MAX_COMMITS]; int commit_count; int selected_commit; NCursesStash stashes[MAX_STASHES]; NCursesBranches branches[MAX_BRANCHES]; int stash_count; int branch_count; int selected_stash; int selected_branch; WINDOW *file_list_win; WINDOW *file_content_win; WINDOW *commit_list_win; WINDOW *stash_list_win; WINDOW *branch_list_win; WINDOW *status_bar_win; int terminal_width; int terminal_height; int file_panel_width; int file_panel_height; int commit_panel_height; int stash_panel_height; int branch_panel_height; int status_bar_height; NCursesViewMode current_mode; SyncStatus sync_status; int spinner_frame; time_t last_sync_time; int animation_frame; int text_char_count; int pushing_branch_index; int pulling_branch_index; SyncStatus branch_push_status; SyncStatus branch_pull_status; int branch_animation_frame; int branch_text_char_count; int critical_operation_in_progress; // Prevent fetching during critical ops } NCursesDiffViewer; /** * Initialize the ncurses diff viewer */ int init_ncurses_diff_viewer(NCursesDiffViewer *viewer); /** * Get list of changed files from git */ int get_ncurses_changed_files(NCursesDiffViewer *viewer); /** * Load full file content with diff highlighting */ int load_full_file_with_diff(NCursesDiffViewer *viewer, const char *filename); /** * Render the file list window */ void render_file_list_window(NCursesDiffViewer *viewer); /** * Render the file content window */ void render_file_content_window(NCursesDiffViewer *viewer); /** * Handle keyboard input for navigation */ int handle_ncurses_diff_input(NCursesDiffViewer *viewer, int key); /** * Run the ncurses diff viewer */ int run_ncurses_diff_viewer(void); /** * Clean up ncurses diff viewer resources */ void cleanup_ncurses_diff_viewer(NCursesDiffViewer *viewer); /** * Create temporary file with current working version */ int create_temp_file_with_changes(const char *filename, char *temp_path); /** * Create temporary file with git HEAD version */ int create_temp_file_git_version(const char *filename, char *temp_path); /** * Get commit history */ int get_commit_history(NCursesDiffViewer *viewer); /** * Toggle file marking for commit */ void toggle_file_mark(NCursesDiffViewer *viewer, int file_index); /** * Mark all files for commit */ void mark_all_files(NCursesDiffViewer *viewer); /** * Commit marked files with title and message */ int commit_marked_files(NCursesDiffViewer *viewer, const char *commit_title, const char *commit_message); /** * Push specific commit */ int push_commit(NCursesDiffViewer *viewer, int commit_index); /** * Pull commits from remote */ int pull_commits(NCursesDiffViewer *viewer); /** * Render the commit list window */ void render_commit_list_window(NCursesDiffViewer *viewer); /** * Get commit title and message input from user */ int get_commit_title_input(char *title, int max_len, char *message, int max_message_len); /** * Draw a box with rounded corners */ void draw_rounded_box(WINDOW *win); /** * Render the status bar */ void render_status_bar(NCursesDiffViewer *viewer); void render_branch_list_window(NCursesDiffViewer *viewer); /** * Update sync status and check for new files */ void update_sync_status(NCursesDiffViewer *viewer); int get_ncurses_git_stashes(NCursesDiffViewer *viewer); int get_ncurses_git_branches(NCursesDiffViewer *viewer); typedef enum { DELETE_LOCAL = 0, DELETE_REMOTE = 1, DELETE_BOTH = 2, DELETE_CANCEL = 3 } DeleteBranchOption; int get_branch_name_input(char *branch_name, int max_len); int create_git_branch(const char *branch_name); int get_rename_branch_input(const char *current_name, char *new_name, int max_len); int rename_git_branch(const char *old_name, const char *new_name); int show_delete_branch_dialog(const char *branch_name); void show_error_popup(const char *error_message); int get_git_remotes(char remotes[][256], int max_remotes); int show_upstream_selection_dialog(const char *branch_name, char *upstream_result, int max_len); int get_current_branch_name(char *branch_name, int max_len); int branch_has_upstream(const char *branch_name); int delete_git_branch(const char *branch_name, DeleteBranchOption option); int create_ncurses_git_stash(NCursesDiffViewer *viewer); int get_stash_name_input(char *stash_name, int max_len); void render_stash_list_window(NCursesDiffViewer *viewer); /** * Load commit details for viewing */ int load_commit_for_viewing(NCursesDiffViewer *viewer, const char *commit_hash); /** * Load stash details for viewing */ int load_stash_for_viewing(NCursesDiffViewer *viewer, int stash_index); #endif // NCURSES_DIFF_VIEWER_H