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