From c37a8f2b4795240b396f583e118a577795439e3d Mon Sep 17 00:00:00 2001 From: savalet Date: Wed, 21 May 2025 23:53:44 +0200 Subject: [PATCH] Add git integration --- src/git.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ src/git.h | 23 +++++++++++++ src/repl/repl.c | 19 ++++++++--- 3 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/git.c create mode 100644 src/git.h diff --git a/src/git.c b/src/git.c new file mode 100644 index 0000000..26c39ed --- /dev/null +++ b/src/git.c @@ -0,0 +1,90 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include +#include +#include + +#include "git.h" + +static +int read_head_branch(char *branch, size_t size) +{ + FILE *f = fopen(".git/HEAD", "r"); + char line[MAX_LINE]; + + if (!f) + return -1; + if (!fgets(line, sizeof(line), f)) { + fclose(f); + return -1; + } + fclose(f); + if (strncmp(line, "ref: refs/heads/", 16) != 0) + return -1; + strncpy(branch, line + 16, size - 1); + branch[strcspn(branch, "\n")] = '\0'; + return 0; +} + +static +int read_git_ref(const char *path, char *hash, size_t size) +{ + FILE *f = fopen(path, "r"); + + if (!f) + return -1; + if (!fgets(hash, size, f)) { + fclose(f); + return -1; + } + fclose(f); + hash[strcspn(hash, "\n")] = '\0'; + return 0; +} + +static +int compare_hashes(const char *local, const char *remote) +{ + if (strcmp(local, remote) == 0) + return 0; + return 1; +} + +static +int analyze_divergence(git_status_t *status) +{ + if (compare_hashes(status->local_hash, status->remote_hash) == 0) { + status->ahead = 0; + status->behind = 0; + } else { + status->ahead = 1; + status->behind = 1; + } + return 0; +} + +bool get_git_status(git_status_t *status) +{ + char local_path[256]; + char remote_path[256]; + + if (read_head_branch(status->branch, sizeof(status->branch)) != 0) + return false; + snprintf(local_path, sizeof(local_path), + ".git/refs/heads/%s", status->branch); + snprintf(remote_path, sizeof(remote_path), + ".git/refs/remotes/origin/%s", status->branch); + if (read_git_ref(local_path, status->local_hash, + sizeof(status->local_hash)) != 0) + return false; + if (read_git_ref(remote_path, status->remote_hash, + sizeof(status->remote_hash)) != 0) + return false; + analyze_divergence(status); + return true; +} diff --git a/src/git.h b/src/git.h new file mode 100644 index 0000000..3cc1107 --- /dev/null +++ b/src/git.h @@ -0,0 +1,23 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#ifndef GIT_H + #define GIT_H + #define MAX_LINE 256 + #define MAX_BRANCH 128 + #define HASH_LEN 41 + +typedef struct { + char branch[MAX_BRANCH]; + char local_hash[HASH_LEN]; + char remote_hash[HASH_LEN]; + int ahead; + int behind; +} git_status_t; + +bool get_git_status(git_status_t *status); +#endif /* GIT_H */ diff --git a/src/repl/repl.c b/src/repl/repl.c index e77b463..c2ccba3 100644 --- a/src/repl/repl.c +++ b/src/repl/repl.c @@ -10,12 +10,13 @@ #include #include +#include "ast.h" #include "common.h" #include "debug.h" +#include "git.h" #include "repl.h" #include "repl/key_handler.h" #include "u_str.h" -#include "visitor.h" #include "vt100_esc_codes.h" const key_handler_t KEY_HANDLERS[] = { @@ -53,20 +54,30 @@ void print_second_shell_prompt(exec_ctx_t *ec) } } +static +void print_git_prompt(git_status_t *gs) +{ + if (!gs->ahead && !gs->behind) + printf(BLUE " [" RED "%s" BLUE "] " RESET "-", gs->branch); +} + static void print_prompt(env_t *env_ptr, char *hostname, exec_ctx_t *ec) { char const *username = get_env_value(env_ptr, "USER"); + git_status_t gs = {0}; if (username == nullptr) username = "?"; printf(BLUE PROMPT_HEADER GREEN "%s" RESET "@" CYAN "%s" BLUE "] " RESET "-" BLUE " [" RESET "%s" BLUE - "] " RESET "-" BLUE " [" YELLOW "%d" BLUE - "]\n└─[" PURPLE "%s%s" BLUE "] " RESET, + "] " RESET "-", username, hostname, - get_env_value(env_ptr, "PWD"), + get_env_value(env_ptr, "PWD")); + if (get_git_status(&gs)) + print_git_prompt(&gs); + printf(BLUE " [" YELLOW "%d" BLUE "]\n└─[" PURPLE "%s%s" BLUE "] " RESET, ec->history_command->sz + 1, ec->history->last_exit_code == 0 ? "" : RED, strcmp(username, "root") == 0 ? "#" : "$");