diff options
Diffstat (limited to '')
-rw-r--r-- | XD.c | 186 |
1 files changed, 186 insertions, 0 deletions
@@ -0,0 +1,186 @@ +#include <stdio.h> +#include <stdlib.h> +#ifdef ERR +#include <stdarg.h> +#include <string.h> +#endif + +#ifdef GIT +#include <git2.h> +#include <git2/common.h> +#include <git2/errors.h> +#include <git2/global.h> +#include <git2/refs.h> +#include <git2/repository.h> +#include <git2/status.h> +#endif + +enum face { EYES, NOSE, MOUTH }; + +void +l(const char *fmt, ...) +{ + #ifdef ERR + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + #endif +} + +#ifdef GIT +/** + * @brief open git repo if one is available at the current path + * + * @return a pointer to the git repo object + */ +git_repository +*init_git() +{ + git_buf buf = GIT_BUF_INIT_CONST(NULL, 0); + git_repository *repo; + + if (git_libgit2_init() < 0) { + l("Failed to initalize libgit2, proceeding without git functionality enabled."); + return NULL; + } + + if (git_repository_discover(&buf, ".", 0, NULL) < 0) { + l("Failed to discover git repo: %s", git_error_last()->message); + return NULL; + } + + if (git_repository_open(&repo, buf.ptr) < 0) { + l("Failed to open git repo: %s", git_error_last()->message); + git_buf_dispose(&buf); + return NULL; + } + + /* get rid of object containing git repo path and return the repo */ + git_buf_dispose(&buf); + return repo; +} + +/** + * @brief check for any existing stashes in the provided git repo + * + * @param repo git repo to check for existing stashes + * @return 1 if stashes found 0 otherwise + */ +int +has_stashes(git_repository *repo) +{ + git_reference *stash = NULL; + int e; + + e = git_reference_lookup(&stash, repo, "refs/stash"); + if (e == GIT_ENOTFOUND) { + git_error_clear(); + return 0; + } else if (e < GIT_OK) { + l("Error looking up stash reference: %s", git_error_last()->message); + return 0; + } else { + e = 1; + } + + git_reference_free(stash); + return e; +} + +/** + * @brief check for any untracked changes in the current git repo + * + * @param repo git repository object + * @return 1 if any untracked changes have been found 0 otherwise + */ +int +has_untracked(git_repository *repo) +{ + git_status_options opts = GIT_STATUS_OPTIONS_INIT; + git_status_list *list = NULL; + int r = 0; + + opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | + GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; + + if (git_status_list_new(&list, repo, &opts) < 0) { + l("Error checking for untacked changes: %s", git_error_last()->message); + return 0; + } + + /* if any changes are found return 1 */ + if (git_status_list_entrycount(list) > 0) { + r = 1; + } + + git_status_list_free(list); + return r; +} +#endif + +int +main(int argc, char *argv[]) +{ + int code = -1; + char face[] = { ':', 0, '|' }; + + #ifdef GIT + git_repository *repo; + int git_ok = 0; + + if ((repo = init_git())) { + git_ok = 1; + } + + if (git_ok) { + /* change the eyes depending on the current git repo's status */ + if (has_stashes(repo)) { + face[EYES] = '8'; /* goggle eyes if we have some stashed changes */ + } else if (git_repository_is_empty(repo)) { + face[EYES] = 'B'; /* sunglasses if we're in a new repo with no HEAD */ + } else { + face[EYES] = ';'; /* wink when we're in a git repo */ + } + + /* change the nose depending on the current git repo's status */ + if (has_untracked(repo)) { + face[NOSE] = '^'; /* add a little nose when there are untracked changes in the repo */ + } else if (git_repository_head_detached(repo)) { + face[NOSE] = '-'; /* add a minus nose when the HEAD is detached */ + } + } + #endif + + /* get exit code from user args */ + code = atoi(argv[1] ? argv[1] : "-1"); + + /* change mouth based on exit code */ + if (code >= 0) { + switch (code) { + case 0: face[MOUTH] = ')'; break; /* all good */ + case 130: face[MOUTH] = 'O'; break; /* Ctrl-c pressed (SIGTERM) */ + case 126: face[MOUTH] = 'P'; break; /* permission denied */ + case 127: face[MOUTH] = '/'; break; /* command not found */ + default: face[MOUTH] = '('; break; /* all other codes (usually the program saying it has failed) */ + } + } else { + face[MOUTH] = '|'; /* no code info */ + } + + #ifdef GIT + git_repository_free(repo); + git_libgit2_shutdown(); + #endif + + printf("%c%c%c", face[EYES], face[NOSE], face[MOUTH]); +} |