2021-02-21 23:40:31 -06:00
|
|
|
#include <string.h>
|
2021-02-21 22:39:58 -06:00
|
|
|
#include <stdio.h>
|
2021-02-21 23:40:31 -06:00
|
|
|
#include <stdlib.h>
|
2021-02-22 01:42:18 -06:00
|
|
|
#include <pthread.h>
|
2021-02-21 22:39:58 -06:00
|
|
|
|
2021-02-21 22:43:22 -06:00
|
|
|
#include "ep.h"
|
2021-02-21 22:39:58 -06:00
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
static char *git_branch_name, *git_status, *git_root;
|
2021-02-21 23:40:31 -06:00
|
|
|
void print_git(void)
|
|
|
|
{
|
|
|
|
if (git_branch_name) {
|
|
|
|
p(" ");
|
|
|
|
p(git_branch_name);
|
|
|
|
|
|
|
|
if (git_status) {
|
|
|
|
p(" [");
|
|
|
|
p(git_status);
|
|
|
|
p("]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct rlfc_data {
|
|
|
|
char *line;
|
|
|
|
size_t n;
|
|
|
|
ssize_t l;
|
|
|
|
int status;
|
|
|
|
};
|
2021-02-21 22:39:58 -06:00
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
static void read_line_from_command(const char *cmd, struct rlfc_data *d)
|
2021-02-21 22:39:58 -06:00
|
|
|
{
|
2021-02-22 01:42:18 -06:00
|
|
|
FILE *f = popen(cmd, "re");
|
2021-02-21 23:40:31 -06:00
|
|
|
if (!f)
|
|
|
|
return;
|
2021-02-21 22:39:58 -06:00
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
d->l = getline(&d->line, &d->n, f);
|
|
|
|
d->status = pclose(f);
|
2021-02-22 01:42:18 -06:00
|
|
|
|
|
|
|
if (d->l > 0) {
|
|
|
|
d->line[d->l-1] = 0;
|
|
|
|
}
|
2021-02-21 23:40:31 -06:00
|
|
|
}
|
2021-02-21 22:39:58 -06:00
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
static void *get_git_status(void *);
|
|
|
|
static void *get_git_root(void *);
|
2021-02-21 23:40:31 -06:00
|
|
|
|
|
|
|
void *git_thread(void *arg)
|
|
|
|
{
|
2021-02-22 01:42:18 -06:00
|
|
|
struct threaded_task *root_lang_task = arg;
|
|
|
|
/* only knows how to launch this task */
|
|
|
|
if (root_lang_task->task != task_launch_root_lang) root_lang_task = NULL;
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
struct rlfc_data c = { 0 };
|
|
|
|
read_line_from_command("git rev-parse --abbrev-ref HEAD 2>/dev/null", &c);
|
|
|
|
|
|
|
|
if (!c.status) {
|
2021-02-21 22:39:58 -06:00
|
|
|
/* if git exits with 0, we are in a repo */
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
if (c.l > 0) {
|
2021-02-21 22:39:58 -06:00
|
|
|
/* TODO: treat case where it reads HEAD */
|
2021-02-22 01:42:18 -06:00
|
|
|
|
2021-02-21 22:39:58 -06:00
|
|
|
/* line ownserhip goes to outside this function */
|
2021-02-21 23:40:31 -06:00
|
|
|
git_branch_name = c.line;
|
2021-02-21 22:39:58 -06:00
|
|
|
}
|
2021-02-21 23:40:31 -06:00
|
|
|
} else {
|
|
|
|
return NULL;
|
2021-02-21 22:39:58 -06:00
|
|
|
}
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
/* since we are in a repo, read git status;
|
|
|
|
* if we add more stuff to do in repos, launch more threads */
|
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
pthread_t status_handle, root_handle;
|
|
|
|
if (pthread_create(&status_handle, NULL, get_git_status, NULL))
|
|
|
|
goto status_create_error;
|
|
|
|
if (pthread_create(&root_handle, NULL, get_git_root, NULL))
|
|
|
|
goto root_create_error;
|
2021-02-21 23:40:31 -06:00
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
void *local_git_root;
|
|
|
|
pthread_join(root_handle, &local_git_root);
|
|
|
|
if (root_lang_task) {
|
|
|
|
root_lang_task->launched = !pthread_create(&root_lang_task->handle, NULL, lang_thread, local_git_root);
|
|
|
|
}
|
|
|
|
root_create_error:
|
|
|
|
pthread_join(status_handle, NULL);
|
|
|
|
status_create_error:
|
2021-02-21 22:39:58 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-02-21 23:40:31 -06:00
|
|
|
|
2021-02-22 00:08:40 -06:00
|
|
|
struct statuses {
|
|
|
|
size_t c;
|
|
|
|
char s[64];
|
|
|
|
char format[3];
|
|
|
|
char prefix;
|
|
|
|
};
|
|
|
|
enum status_index { added, deleted, modified_unstaged, modified_staged, untracked, status_index_n };
|
|
|
|
|
2021-02-22 01:42:18 -06:00
|
|
|
static void *get_git_status(void *arg)
|
2021-02-21 23:40:31 -06:00
|
|
|
{
|
2021-02-22 01:42:18 -06:00
|
|
|
(void)arg;
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
FILE *f = popen("git status --porcelain=v1 -z 2>/dev/null", "re");
|
|
|
|
if (!f)
|
|
|
|
return NULL;
|
|
|
|
|
2021-02-22 00:08:40 -06:00
|
|
|
struct statuses g[status_index_n] = {
|
|
|
|
[added] = { .format = "A ", .prefix = '+' },
|
|
|
|
[deleted] = { .format = "D ", .prefix = '-' },
|
|
|
|
[modified_unstaged] = { .format = " M", .prefix = '~' },
|
|
|
|
[modified_staged] = { .format = "M ", .prefix = '>' },
|
|
|
|
[untracked] = { .format = "??", .prefix = '+' },
|
|
|
|
};
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
char *line = NULL;
|
|
|
|
size_t n = 0;
|
|
|
|
ssize_t l;
|
|
|
|
while ((l = getdelim(&line, &n, 0, f)) != -1) {
|
2021-02-22 00:08:40 -06:00
|
|
|
if (l > 4) {
|
|
|
|
for (int i = 0; i < status_index_n; i++) {
|
|
|
|
g[i].c += !strncmp(g[i].format, line, 2);
|
|
|
|
}
|
|
|
|
}
|
2021-02-21 23:40:31 -06:00
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
|
2021-02-22 00:08:40 -06:00
|
|
|
/* cheat to display added+modified_staged in one place */
|
|
|
|
g[added].c += g[modified_staged].c;
|
|
|
|
|
2021-02-21 23:40:31 -06:00
|
|
|
if (!pclose(f)) {
|
2021-02-22 00:08:40 -06:00
|
|
|
for (int i = 0; i < status_index_n; i++) {
|
|
|
|
if (g[i].c) {
|
|
|
|
snprintf(g[i].s, sizeof(g[i].s), "%c%zu", g[i].prefix, g[i].c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (asprintf(&git_status, "%s%s%s", g[added].s, g[deleted].s, g[modified_unstaged].s) == 0) {
|
|
|
|
/* if string is empty, don't display it */
|
|
|
|
free(git_status);
|
|
|
|
git_status = NULL;
|
|
|
|
}
|
2021-02-21 23:40:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return git_status;
|
|
|
|
}
|
2021-02-22 01:42:18 -06:00
|
|
|
|
|
|
|
static void *get_git_root(void *arg)
|
|
|
|
{
|
|
|
|
(void)arg;
|
|
|
|
|
|
|
|
struct rlfc_data c = { 0 };
|
|
|
|
read_line_from_command("git rev-parse --show-toplevel 2>/dev/null", &c);
|
|
|
|
|
|
|
|
if (c.l > 0)
|
|
|
|
git_root = c.line;
|
|
|
|
|
|
|
|
return git_root;
|
|
|
|
}
|