Commit | Line | Data |
---|---|---|
a74fa190 | 1 | /* Cursed git browser |
800a900c | 2 | * |
a74fa190 | 3 | * Copyright (c) Jonas Fonseca, 2006 |
800a900c | 4 | * |
a74fa190 JF |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
800a900c JF |
9 | */ |
10 | ||
e3e7b9fc | 11 | #include <stdarg.h> |
800a900c JF |
12 | #include <stdlib.h> |
13 | #include <stdio.h> | |
e3e7b9fc | 14 | #include <string.h> |
800a900c JF |
15 | #include <ctype.h> |
16 | #include <signal.h> | |
17 | ||
18 | #include <curses.h> | |
19 | ||
e3e7b9fc | 20 | |
a74fa190 JF |
21 | #define MSG_HELP "(q)uit, (s)hell, (j) down, (k) up" |
22 | ||
05f1685b JF |
23 | #define KEY_ESC 27 |
24 | #define KEY_TAB 9 | |
25 | ||
e3e7b9fc | 26 | //WINDOW *titlewin; |
05f1685b JF |
27 | WINDOW *mainwin; |
28 | WINDOW *statuswin; | |
29 | ||
a74fa190 | 30 | typedef void (*pipe_reader_T)(char *, int); |
05f1685b JF |
31 | |
32 | FILE *pipe; | |
33 | long pipe_lineno; | |
a74fa190 | 34 | pipe_reader_T pipe_reader; |
05f1685b | 35 | |
e3e7b9fc JF |
36 | |
37 | static void | |
38 | put_status(char *msg, ...) | |
39 | { | |
40 | va_list args; | |
41 | ||
42 | va_start(args, msg); | |
43 | werase(statuswin); | |
44 | wmove(statuswin, 0, 0); | |
45 | vwprintw(statuswin, msg, args); | |
46 | wrefresh(statuswin); | |
47 | va_end(args); | |
48 | } | |
49 | ||
800a900c JF |
50 | /* |
51 | * Init and quit | |
52 | */ | |
53 | ||
05f1685b JF |
54 | static void |
55 | quit(int sig) | |
800a900c JF |
56 | { |
57 | endwin(); | |
58 | ||
59 | /* do your non-curses wrapup here */ | |
60 | ||
61 | exit(0); | |
62 | } | |
63 | ||
64 | static void | |
65 | init_colors(void) | |
66 | { | |
05f1685b JF |
67 | int bg = COLOR_BLACK; |
68 | ||
800a900c JF |
69 | start_color(); |
70 | ||
e3e7b9fc | 71 | if (use_default_colors() != ERR) |
05f1685b JF |
72 | bg = -1; |
73 | ||
74 | init_pair(COLOR_BLACK, COLOR_BLACK, bg); | |
75 | init_pair(COLOR_GREEN, COLOR_GREEN, bg); | |
76 | init_pair(COLOR_RED, COLOR_RED, bg); | |
77 | init_pair(COLOR_CYAN, COLOR_CYAN, bg); | |
78 | init_pair(COLOR_WHITE, COLOR_WHITE, bg); | |
79 | init_pair(COLOR_MAGENTA, COLOR_MAGENTA, bg); | |
80 | init_pair(COLOR_BLUE, COLOR_BLUE, bg); | |
81 | init_pair(COLOR_YELLOW, COLOR_YELLOW, bg); | |
800a900c JF |
82 | } |
83 | ||
84 | static void | |
85 | init(void) | |
86 | { | |
05f1685b | 87 | int x, y; |
800a900c | 88 | |
05f1685b JF |
89 | signal(SIGINT, quit); |
90 | ||
91 | initscr(); /* initialize the curses library */ | |
92 | nonl(); /* tell curses not to do NL->CR/NL on output */ | |
93 | cbreak(); /* take input chars one at a time, no wait for \n */ | |
94 | noecho(); /* don't echo input */ | |
e3e7b9fc | 95 | leaveok(stdscr, TRUE); |
800a900c JF |
96 | |
97 | if (has_colors()) | |
98 | init_colors(); | |
05f1685b JF |
99 | |
100 | getmaxyx(stdscr, y, x); | |
101 | ||
e3e7b9fc JF |
102 | #if 0 |
103 | titlewin = newwin(1, 0, y - 2, 0); | |
05f1685b JF |
104 | |
105 | wattrset(titlewin, COLOR_PAIR(COLOR_GREEN)); | |
106 | waddch(titlewin, ACS_VLINE); | |
107 | wprintw(titlewin, "%s", "cg-view"); | |
108 | waddch(titlewin, ACS_LTEE); | |
109 | whline(titlewin, ACS_HLINE, x); | |
110 | wrefresh(titlewin); | |
e3e7b9fc | 111 | #endif |
05f1685b JF |
112 | statuswin = newwin(1, 0, y - 1, 0); |
113 | ||
114 | wattrset(statuswin, COLOR_PAIR(COLOR_GREEN)); | |
a74fa190 | 115 | put_status(MSG_HELP); |
05f1685b | 116 | |
e3e7b9fc | 117 | mainwin = newwin(y - 1, 0, 0, 0); |
05f1685b JF |
118 | scrollok(mainwin, TRUE); |
119 | keypad(mainwin, TRUE); /* enable keyboard mapping */ | |
120 | } | |
121 | ||
122 | /* | |
a74fa190 | 123 | * Pipe readers |
05f1685b JF |
124 | */ |
125 | ||
126 | #define DIFF_CMD \ | |
e3e7b9fc | 127 | "git-rev-list HEAD^..HEAD | " \ |
a74fa190 | 128 | "git-diff-tree --stdin --pretty -r --cc --always --stat" |
05f1685b JF |
129 | |
130 | ||
a74fa190 | 131 | #define LOG_CMD0 \ |
05f1685b | 132 | "git-rev-list $(git-rev-parse --since=1.month) HEAD | " \ |
67392cc4 | 133 | "git-diff-tree --stdin --pretty -r --root" |
05f1685b | 134 | |
a74fa190 JF |
135 | #define LOG_CMD \ |
136 | "git-rev-list HEAD | git-diff-tree --stdin --pretty -r --root" | |
137 | ||
05f1685b | 138 | static void |
a74fa190 | 139 | log_reader(char *line, int lineno) |
05f1685b | 140 | { |
a74fa190 | 141 | static int log_reader_skip; |
05f1685b JF |
142 | |
143 | if (!line) { | |
144 | wattrset(mainwin, A_NORMAL); | |
a74fa190 | 145 | log_reader_skip = 0; |
05f1685b JF |
146 | return; |
147 | } | |
148 | ||
149 | if (!strncmp("commit ", line, 7)) { | |
a74fa190 | 150 | wattrset(mainwin, COLOR_PAIR(COLOR_GREEN)); |
05f1685b JF |
151 | |
152 | } else if (!strncmp("Author: ", line, 8)) { | |
153 | wattrset(mainwin, COLOR_PAIR(COLOR_CYAN)); | |
154 | ||
155 | } else if (!strncmp("Date: ", line, 6)) { | |
156 | wattrset(mainwin, COLOR_PAIR(COLOR_YELLOW)); | |
157 | ||
158 | } else if (!strncmp("diff --git ", line, 11)) { | |
159 | wattrset(mainwin, COLOR_PAIR(COLOR_YELLOW)); | |
160 | ||
161 | } else if (!strncmp("diff-tree ", line, 10)) { | |
162 | wattrset(mainwin, COLOR_PAIR(COLOR_BLUE)); | |
163 | ||
164 | } else if (!strncmp("index ", line, 6)) { | |
165 | wattrset(mainwin, COLOR_PAIR(COLOR_BLUE)); | |
166 | ||
167 | } else if (line[0] == '-') { | |
168 | wattrset(mainwin, COLOR_PAIR(COLOR_RED)); | |
169 | ||
170 | } else if (line[0] == '+') { | |
171 | wattrset(mainwin, COLOR_PAIR(COLOR_GREEN)); | |
172 | ||
173 | } else if (line[0] == '@') { | |
174 | wattrset(mainwin, COLOR_PAIR(COLOR_MAGENTA)); | |
175 | ||
176 | } else if (line[0] == ':') { | |
67392cc4 | 177 | pipe_lineno--; |
a74fa190 | 178 | log_reader_skip = 1; |
05f1685b JF |
179 | return; |
180 | ||
a74fa190 | 181 | } else if (log_reader_skip) { |
67392cc4 | 182 | pipe_lineno--; |
a74fa190 | 183 | log_reader_skip = 0; |
05f1685b JF |
184 | return; |
185 | ||
186 | } else { | |
187 | wattrset(mainwin, A_NORMAL); | |
188 | } | |
189 | ||
190 | mvwaddstr(mainwin, lineno, 0, line); | |
191 | } | |
192 | ||
193 | static FILE * | |
a74fa190 | 194 | open_pipe(char *cmd, pipe_reader_T reader) |
05f1685b JF |
195 | { |
196 | pipe = popen(cmd, "r"); | |
e3e7b9fc | 197 | pipe_lineno = 0; |
a74fa190 | 198 | pipe_reader = reader; |
e3e7b9fc JF |
199 | wclear(mainwin); |
200 | wmove(mainwin, 0, 0); | |
201 | put_status("Loading..."); | |
05f1685b JF |
202 | return pipe; |
203 | } | |
204 | ||
205 | static void | |
206 | read_pipe(int lines) | |
207 | { | |
208 | char buffer[BUFSIZ]; | |
209 | char *line; | |
e3e7b9fc | 210 | int x, y; |
05f1685b JF |
211 | |
212 | while ((line = fgets(buffer, sizeof(buffer), pipe))) { | |
e3e7b9fc JF |
213 | int linelen; |
214 | ||
05f1685b JF |
215 | if (!--lines) |
216 | break; | |
e3e7b9fc JF |
217 | |
218 | linelen = strlen(line); | |
219 | if (linelen) | |
220 | line[linelen - 1] = 0; | |
221 | ||
a74fa190 | 222 | pipe_reader(line, pipe_lineno++); |
05f1685b JF |
223 | } |
224 | ||
225 | if (feof(pipe) || ferror(pipe)) { | |
a74fa190 | 226 | pipe_reader(NULL, pipe_lineno - 1); |
05f1685b JF |
227 | pclose(pipe); |
228 | pipe = NULL; | |
a74fa190 JF |
229 | pipe_reader = NULL; |
230 | put_status("%s (lines %d)", MSG_HELP, pipe_lineno - 1); | |
05f1685b | 231 | } |
800a900c JF |
232 | } |
233 | ||
234 | /* | |
235 | * Main | |
236 | */ | |
237 | ||
238 | int | |
239 | main(int argc, char *argv[]) | |
240 | { | |
800a900c JF |
241 | init(); |
242 | ||
a74fa190 | 243 | //pipe = open_pipe(LOG_CMD, log_reader); |
800a900c JF |
244 | |
245 | for (;;) { | |
05f1685b JF |
246 | int c; |
247 | ||
248 | if (pipe) read_pipe(20); | |
249 | if (pipe) nodelay(mainwin, TRUE); | |
250 | ||
251 | c = wgetch(mainwin); /* refresh, accept single keystroke of input */ | |
252 | ||
253 | if (pipe) nodelay(mainwin, FALSE); | |
254 | ||
e3e7b9fc | 255 | /* No input from wgetch() with nodelay() enabled. */ |
05f1685b JF |
256 | if (c == ERR) |
257 | continue; | |
800a900c JF |
258 | |
259 | /* Process the command keystroke */ | |
260 | switch (c) { | |
05f1685b | 261 | case KEY_ESC: |
800a900c JF |
262 | case 'q': |
263 | quit(0); | |
264 | return 0; | |
265 | ||
05f1685b JF |
266 | case KEY_DOWN: |
267 | case 'j': | |
268 | wscrl(mainwin, 1); | |
269 | break; | |
270 | ||
271 | case KEY_UP: | |
272 | case 'k': | |
273 | wscrl(mainwin, -1); | |
274 | break; | |
275 | ||
e3e7b9fc JF |
276 | case 'c': |
277 | wclear(mainwin); | |
278 | break; | |
279 | ||
05f1685b | 280 | case 'd': |
a74fa190 | 281 | pipe = open_pipe(DIFF_CMD, log_reader); |
05f1685b JF |
282 | break; |
283 | ||
284 | case 'l': | |
a74fa190 | 285 | pipe = open_pipe(LOG_CMD, log_reader); |
05f1685b JF |
286 | break; |
287 | ||
800a900c | 288 | case 's': |
e3e7b9fc | 289 | mvwaddstr(statuswin, 0, 0, "Shelling out..."); |
800a900c JF |
290 | def_prog_mode(); /* save current tty modes */ |
291 | endwin(); /* restore original tty modes */ | |
292 | system("sh"); /* run shell */ | |
05f1685b | 293 | |
e3e7b9fc | 294 | werase(statuswin); |
a74fa190 | 295 | mvwaddstr(statuswin, 0, 0, MSG_HELP); |
800a900c | 296 | reset_prog_mode(); |
800a900c | 297 | break; |
800a900c JF |
298 | } |
299 | ||
05f1685b JF |
300 | redrawwin(mainwin); |
301 | wrefresh(mainwin); | |
800a900c JF |
302 | } |
303 | ||
304 | quit(0); | |
305 | } |