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 }