Files
ferrum-old/include/ui/ncurses_diff_viewer.h

401 lines
13 KiB
C

#ifndef NCURSES_DIFF_VIEWER_H
#define NCURSES_DIFF_VIEWER_H
#include "common.h"
#include <ncurses.h>
#define MAX_FILES 100
#define MAX_FILENAME_LEN 256
#define MAX_FULL_FILE_LINES 2000
#define MAX_COMMITS 1000
#define MAX_COMMIT_TITLE_LEN 256
#define MAX_AUTHOR_INITIALS 3
#define MAX_STASHES 100
#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
int has_staged_changes;
} 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
int hunk_id;
int is_staged;
int line_number_old;
int line_number_new;
int is_context;
} 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_LIST,
NCURSES_MODE_BRANCH_VIEW
} 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;
int commit_count;
int commit_capacity;
int selected_commit;
int commit_scroll_offset;
NCursesStash stashes[MAX_STASHES];
NCursesBranches branches[MAX_BRANCHES];
int stash_count;
int branch_count;
int selected_stash;
int stash_scroll_offset;
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
// Background fetch management
pid_t fetch_pid; // Process ID of background fetch
int fetch_in_progress; // Flag to track if fetch is running
// Branch-specific commits for hover functionality
char branch_commits[MAX_COMMITS][2048]; // Larger buffer for formatted commits
int branch_commit_count;
char current_branch_for_commits[MAX_BRANCHNAME_LEN];
int branch_commits_scroll_offset;
int branch_commits_cursor_line;
int split_view_mode; // 0 = normal view, 1 = split staged/unstaged
int staged_scroll_offset; // Scroll position for staged pane
int active_pane; // 0 = unstaged, 1 = staged
char current_file_path[512]; // Path of currently viewed file
int total_hunks; // Total number of hunks in current file
NCursesFileLine
staged_lines[MAX_FULL_FILE_LINES]; // Separate storage for staged content
int staged_line_count; // Number of lines in staged view
int staged_cursor_line;
// Fuzzy search state
int fuzzy_search_active; // 1 if fuzzy search is active
char fuzzy_search_query[256]; // Current search query
int fuzzy_search_query_len; // Length of current query
// Scored search results
struct {
int file_index;
int score;
} fuzzy_scored_files[MAX_FILES]; // Scored and sorted results
int fuzzy_filtered_count; // Number of filtered files
int fuzzy_selected_index; // Currently selected in fuzzy list
int fuzzy_scroll_offset; // Scroll position in fuzzy list
WINDOW *fuzzy_input_win; // Input window for search
WINDOW *fuzzy_list_win; // Results list window
// State tracking to prevent unnecessary redraws
int fuzzy_needs_full_redraw; // 1 if full redraw needed (borders, input, list)
int fuzzy_needs_input_redraw; // 1 if input field needs redraw
int fuzzy_needs_list_redraw; // 1 if file list needs redraw
char fuzzy_last_query[256]; // Last rendered query
int fuzzy_last_selected; // Last rendered selection
int fuzzy_last_scroll; // Last rendered scroll position
int fuzzy_last_filtered_count; // Last rendered result count
// Generic grep search state (for commits, stashes, branches)
int grep_search_active; // 1 if grep search is active
NCursesViewMode grep_search_mode; // Which mode grep is searching in
char grep_search_query[256]; // Current search query
int grep_search_query_len; // Length of current query
// Scored grep search results
struct {
int item_index;
int score;
} grep_scored_items[MAX_COMMITS]; // Scored and sorted results (reuse
// MAX_COMMITS)
int grep_filtered_count; // Number of filtered items
int grep_selected_index; // Currently selected in grep list
int grep_scroll_offset; // Scroll position in grep list
WINDOW *grep_input_win; // Input window for search
WINDOW *grep_list_win; // Results list window
WINDOW *grep_preview_win; // Grep search preview
// State tracking for grep search rendering
int grep_needs_full_redraw; // 1 if full redraw needed
int grep_needs_input_redraw; // 1 if input field needs redraw
int grep_needs_list_redraw; // 1 if item list needs redraw
char grep_last_query[256]; // Last rendered query
int grep_last_selected; // Last rendered selection
int grep_last_scroll; // Last rendered scroll position
int grep_last_filtered_count; // Last rendered result count
} NCursesDiffViewer;
int init_ncurses_diff_viewer(NCursesDiffViewer *viewer);
int get_ncurses_changed_files(NCursesDiffViewer *viewer);
int load_full_file_with_diff(NCursesDiffViewer *viewer, const char *filename);
void render_file_list_window(NCursesDiffViewer *viewer);
void render_file_content_window(NCursesDiffViewer *viewer);
int handle_ncurses_diff_input(NCursesDiffViewer *viewer, int key);
int run_ncurses_diff_viewer(void);
void cleanup_ncurses_diff_viewer(NCursesDiffViewer *viewer);
int create_temp_file_with_changes(const char *filename, char *temp_path);
int create_temp_file_git_version(const char *filename, char *temp_path);
int get_commit_history(NCursesDiffViewer *viewer);
void toggle_file_mark(NCursesDiffViewer *viewer, int file_index);
void mark_all_files(NCursesDiffViewer *viewer);
int commit_marked_files(NCursesDiffViewer *viewer, const char *commit_title,
const char *commit_message);
int push_commit(NCursesDiffViewer *viewer, int commit_index);
int pull_commits(NCursesDiffViewer *viewer);
void render_commit_list_window(NCursesDiffViewer *viewer);
int get_commit_title_input(char *title, int max_len, char *message,
int max_message_len);
void draw_rounded_box(WINDOW *win);
void render_status_bar(NCursesDiffViewer *viewer);
void render_branch_list_window(NCursesDiffViewer *viewer);
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);
int load_commit_for_viewing(NCursesDiffViewer *viewer, const char *commit_hash);
int load_stash_for_viewing(NCursesDiffViewer *viewer, int stash_index);
int load_branch_commits(NCursesDiffViewer *viewer, const char *branch_name);
int parse_branch_commits_to_lines(NCursesDiffViewer *viewer);
void start_background_fetch(NCursesDiffViewer *viewer);
void check_background_fetch(NCursesDiffViewer *viewer);
void move_cursor_smart(NCursesDiffViewer *viewer, int direction);
void move_cursor_smart_unstaged(NCursesDiffViewer *viewer, int direction);
void move_cursor_smart_staged(NCursesDiffViewer *viewer, int direction);
int wrap_line_to_width(const char *input_line, char wrapped_lines[][1024],
int max_lines, int width);
int render_wrapped_line(WINDOW *win, const char *line, int start_y, int start_x,
int width, int max_rows, int color_pair, int reverse);
int calculate_wrapped_line_height(const char *line, int width);
int load_file_preview(NCursesDiffViewer *viewer, const char *filename);
void update_preview_for_current_selection(NCursesDiffViewer *viewer);
int get_single_input(const char *title, const char *prompt, char *input,
int input_len, int is_password);
int get_github_credentials(char *username, int username_len, char *token,
int token_len);
int execute_git_with_auth(const char *base_cmd, const char *username,
const char *token);
int stage_hunk_by_line(NCursesDiffViewer *viewer, int line_index);
int load_file_with_staging_info(NCursesDiffViewer *viewer,
const char *filename);
void rebuild_staged_view(NCursesDiffViewer *viewer);
int apply_staged_changes(NCursesDiffViewer *viewer);
int reset_staged_changes(NCursesDiffViewer *viewer);
int unstage_line_from_git(NCursesDiffViewer *viewer, int staged_line_index);
int commit_staged_changes_only(NCursesDiffViewer *viewer,
const char *commit_title,
const char *commit_message);
void rebuild_staged_view_from_git(NCursesDiffViewer *viewer);
void init_fuzzy_search(NCursesDiffViewer *viewer);
void cleanup_fuzzy_search(NCursesDiffViewer *viewer);
void enter_fuzzy_search_mode(NCursesDiffViewer *viewer);
void exit_fuzzy_search_mode(NCursesDiffViewer *viewer);
void update_fuzzy_filter(NCursesDiffViewer *viewer);
void render_fuzzy_search(NCursesDiffViewer *viewer);
void render_fuzzy_input(NCursesDiffViewer *viewer);
void render_fuzzy_list_content(NCursesDiffViewer *viewer);
void create_fuzzy_windows_with_borders(NCursesDiffViewer *viewer);
int handle_fuzzy_search_input(NCursesDiffViewer *viewer, int key);
void select_fuzzy_file(NCursesDiffViewer *viewer);
void init_grep_search(NCursesDiffViewer *viewer);
void cleanup_grep_search(NCursesDiffViewer *viewer);
void enter_grep_search_mode(NCursesDiffViewer *viewer);
void exit_grep_search_mode(NCursesDiffViewer *viewer);
void update_grep_filter(NCursesDiffViewer *viewer);
void render_grep_search(NCursesDiffViewer *viewer);
int handle_grep_search_input(NCursesDiffViewer *viewer, int key);
void select_grep_item(NCursesDiffViewer *viewer);
int calculate_grep_score(const char *pattern, const char *text);
void extract_branch_from_stash(const char *stash_info, char *branch_name,
int max_len);
#endif // NCURSES_DIFF_VIEWER_H