-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit.c
132 lines (115 loc) · 3.72 KB
/
git.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "git.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdbool.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// DIFF-HL
Diffs getDiffInfo(const char *filePath) {
Diffs diffs = {NULL, 0, 0};
char command[1024];
FILE *fp;
snprintf(command, sizeof(command), "git diff --no-color --unified=0 %s",
filePath);
fp = popen(command, "r");
if (fp == NULL) {
return diffs;
}
char line[256];
int currentLine = 1;
bool inHunk = false;
int hunkNewStart = 0;
int deletionCount = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
if (line[0] == '@' && line[1] == '@') {
sscanf(line, "@@ -%*d,%*d +%d,%*d @@", &hunkNewStart);
currentLine = hunkNewStart;
inHunk = true;
deletionCount = 0;
} else if (inHunk) {
if (diffs.count == diffs.capacity) {
diffs.capacity = diffs.capacity == 0 ? 1 : diffs.capacity * 2;
diffs.array = realloc(diffs.array, diffs.capacity * sizeof(DiffInfo));
}
DiffInfo diff = {currentLine, DIFF_NONE};
switch (line[0]) {
case '+':
if (deletionCount > 0) {
diff.type = DIFF_CHANGED;
deletionCount--;
} else {
diff.type = DIFF_ADDED;
}
diffs.array[diffs.count++] = diff;
currentLine++;
break;
case '-':
// Track deletions but do not add to diffs.array
deletionCount++;
break;
case ' ':
currentLine++;
deletionCount = 0;
break;
default:
inHunk = false;
break;
}
}
}
pclose(fp);
return diffs;
}
char* getGitBranch(const char* relativePath) {
char fullPath[1024];
char* homedir;
char* projectDir;
char git_head_path[1024];
char* branch_name = NULL;
FILE* head_file;
char line[256];
// Expand the ~ to the full home directory path
if (relativePath[0] == '~' && relativePath[1] == '/') {
homedir = getenv("HOME");
if (homedir == NULL) {
homedir = getpwuid(getuid())->pw_dir;
}
snprintf(fullPath, sizeof(fullPath), "%s%s", homedir, relativePath + 1);
} else {
strncpy(fullPath, relativePath, sizeof(fullPath));
}
// Find the project directory (parent of the file)
projectDir = strdup(fullPath);
char* lastSlash = strrchr(projectDir, '/');
if (lastSlash != NULL) {
*lastSlash = '\0'; // Truncate at the last slash
}
// Construct the path to the .git/HEAD file
snprintf(git_head_path, sizeof(git_head_path), "%s/.git/HEAD", projectDir);
// Check if the .git directory exists
struct stat st;
if (stat(git_head_path, &st) == -1) {
free(projectDir);
return strdup(""); // Not a git repository (we do it like this for the modeline)
}
head_file = fopen(git_head_path, "r");
if (head_file == NULL) {
free(projectDir);
return strdup(""); // Unable to open HEAD file
}
if (fgets(line, sizeof(line), head_file) != NULL) {
char* ref_prefix = "ref: refs/heads/";
if (strncmp(line, ref_prefix, strlen(ref_prefix)) == 0) {
// Remove newline character if present
char* newline = strchr(line, '\n');
if (newline) *newline = '\0';
branch_name = strdup(line + strlen(ref_prefix));
}
}
fclose(head_file);
free(projectDir);
return branch_name ? branch_name : strdup("");
}