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