chiark / gitweb /
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);*/