feat: Add interactive line-by-line staging to ncurses diff viewer

Implement comprehensive interactive staging functionality that allows
users
to stage and unstage individual lines, similar to `git add -p` but with
a
visual interface.

New features:
- Split view mode showing unstaged changes (left) and staged changes
(right)
- Line-by-line staging: press Space on any diff line to stage/unstage it
- Tab switching between unstaged and staged panes
- Apply staged changes with 'a' key (runs `git apply --cached`)
- Visual indicators for staged vs unstaged content with proper syntax
highlighting
- Interactive unstaging: switch to staged pane and press Space to
unstage lines
- Automatic refresh of git status after staging/unstaging operations
- Proper git integration reading from both working directory and staging
area

Technical implementation:
- Added `load_file_with_staging_info()` to load unstaged changes
(staging vs working)
- Added `rebuild_staged_view_from_git()` to load staged changes (HEAD vs
staging)
- Added `stage_hunk_by_line()` for individual line staging
- Added `unstage_line_from_git()` for removing lines from staging area
- Added `apply_staged_changes()` to apply staged content to git
- Enhanced file content window with split view rendering
- Added proper cursor management for both unstaged and staged panes

This transforms the diff viewer into a full-featured interactive staging
tool,
allowing developers to create atomic commits with only specific lines
rather
than entire files.

Keybindings:
- Enter: Switch to split staging view
- Tab: Switch between unstaged/staged panes
- Space: Stage/unstage current line
- 'a': Apply staged changes to git
- 'c': Commit staged changes
- 'r': Reset staged changes
This commit is contained in:
2025-06-13 16:33:45 +02:00
parent 30935b34ba
commit f59381f929
7 changed files with 883 additions and 1018 deletions

Binary file not shown.

View File

@@ -1412,7 +1412,7 @@ char ***lsh_split_piped_line(char *line) {
}
// First split by pipe character
cmd_str = strtok_r(line, "|", &save_ptr);
cmd_str = strtok_r(line, "|", &save_ptr);
while (cmd_str != NULL) {
// Allocate space for this command

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@ 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 {
@@ -40,6 +41,11 @@ 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 {
@@ -138,6 +144,16 @@ typedef struct {
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;
} NCursesDiffViewer;
/**
@@ -331,4 +347,23 @@ int get_github_credentials(char *username, int username_len, char *token,
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 laod_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);
#endif // NCURSES_DIFF_VIEWER_H

Binary file not shown.

BIN
shell

Binary file not shown.

BIN
weather.o

Binary file not shown.