Exploration
authorJonas Fonseca <fonseca@diku.dk>
Sat, 22 Apr 2006 19:39:33 +0000 (21:39 +0200)
committerJonas Fonseca <fonseca@antimatter.localdomain>
Sat, 22 Apr 2006 19:39:33 +0000 (21:39 +0200)
Makefile
asciidoc.conf [new file with mode: 0644]
cgit.c

index eec1e03..efeca0d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,31 @@
 LDFLAGS = -lcurses
 CFLAGS = -g
+PROGS  = cgit
+DOCS   = cgit.1.txt cgit.1 cgit.1.html
 
-all: cgit
+all: $(PROGS)
+docs: $(DOCS)
 
 install: all
-       install cgit $(HOME)/bin
+       for prog in $(PROGS); do \
+               install $$prog $(HOME)/bin; \
+       done
 
 clean:
-       rm -f cgit
+       rm -f $(PROGS) $(DOCS)
 
 cgit: cgit.c
+
+cgit.1.txt: cgit.c
+       sed -n '/\*\*/,/\*\*/p' < $< | \
+       sed '/\*\*/d' | \
+       sed -n 's/^ \* *//p' > $@
+
+%.1.html : %.1.txt
+       asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<
+
+%.1.xml : %.1.txt
+       asciidoc -b docbook -d manpage -f asciidoc.conf $<
+
+%.1 : %.1.xml
+       xmlto man $<
diff --git a/asciidoc.conf b/asciidoc.conf
new file mode 100644 (file)
index 0000000..e4178cc
--- /dev/null
@@ -0,0 +1,25 @@
+## gitlink: macro
+#
+# Usage: gitlink:command[manpage-section]
+#
+# Note, {0} is the manpage section, while {target} is the command.
+#
+# Show GIT link as: <command>(<section>); if section is defined, else just show
+# the command.
+
+ifdef::backend-docbook[]
+[gitlink-inlinemacro]
+{0%{target}}
+{0#<citerefentry>}
+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+{0#</citerefentry>}
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[gitlink-inlinemacro]
+<a href="{target}{0?.{0}}.html">{target}{0?({0})}</a>
+endif::backend-xhtml11[]
+
+[attributes]
+# Five non breaking spaces used for option indentation in the quick reference
+cg-refopt=&#160;&#160;&#160;&#160;&#160;
diff --git a/cgit.c b/cgit.c
index a05103e..20d58fa 100644 (file)
--- a/cgit.c
+++ b/cgit.c
@@ -1,12 +1,21 @@
-/* Cursed git browser
+/**
+ * gitzilla(1)
+ * ===========
  *
- * Copyright (c) Jonas Fonseca, 2006
+ * NAME
+ * ----
+ * gitzilla - cursed git browser
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+ * SYNOPSIS
+ * --------
+ * gitzilla
+ *
+ * DESCRIPTION
+ * -----------
+ *
+ * a
+ *
+ **/
 
 #include <stdarg.h>
 #include <stdlib.h>
 
 #include <curses.h>
 
+/**
+ * OPTIONS
+ * -------
+ *
+ * None
+ *
+ **/
+
+/**
+ * KEYS
+ * ----
+ *
+ * q:: quit
+ * s:: shell
+ * j:: down
+ * k:: up
+ *
+ **/
 
 #define MSG_HELP "(q)uit, (s)hell, (j) down, (k) up"
 
 #define KEY_ESC        27
 #define KEY_TAB        9
 
-//WINDOW *titlewin;
-WINDOW *mainwin;
-WINDOW *statuswin;
+struct view {
+       WINDOW *win;
 
-typedef void (*pipe_reader_T)(char *, int);
+       char *cmd;
+       void (*reader)(char *, int);
+       FILE *pipe;
 
-FILE *pipe;
-long  pipe_lineno;
-pipe_reader_T pipe_reader;
+       unsigned long lines;
+       unsigned long lineno;
+};
 
+static struct view main_view;
+static struct view diff_view;
+static struct view log_view;
+static struct view status_view;
+
+int do_resize = 1;
 
 static void
 put_status(char *msg, ...)
@@ -40,13 +74,36 @@ put_status(char *msg, ...)
        va_list args;
 
        va_start(args, msg);
-       werase(statuswin);
-       wmove(statuswin, 0, 0);
-       vwprintw(statuswin, msg, args);
-       wrefresh(statuswin);
+       werase(status_view.win);
+       wmove(status_view.win, 0, 0);
+       vwprintw(status_view.win, msg, args);
+       wrefresh(status_view.win);
        va_end(args);
 }
 
+static void
+resize_views(void)
+{
+       int x, y;
+
+       getmaxyx(stdscr, y, x);
+
+       if (status_view.win)
+               delwin(status_view.win);
+       status_view.win = newwin(1, 0, y - 1, 0);
+
+       wattrset(status_view.win, COLOR_PAIR(COLOR_GREEN));
+       put_status(MSG_HELP);
+
+       if (main_view.win)
+               delwin(main_view.win);
+       main_view.win = newwin(y - 1, 0, 0, 0);
+
+       scrollok(main_view.win, TRUE);
+       keypad(main_view.win, TRUE);  /* enable keyboard mapping */
+       put_status("%d %d", y, x);
+}
+
 /*
  * Init and quit
  */
@@ -84,8 +141,6 @@ init_colors(void)
 static void
 init(void)
 {
-       int x, y;
-
        signal(SIGINT, quit);
 
        initscr();      /* initialize the curses library */
@@ -93,30 +148,10 @@ init(void)
        cbreak();       /* take input chars one at a time, no wait for \n */
        noecho();       /* don't echo input */
        leaveok(stdscr, TRUE);
+       /* curs_set(0); */
 
        if (has_colors())
                init_colors();
-
-       getmaxyx(stdscr, y, x);
-
-#if 0
-       titlewin = newwin(1, 0, y - 2, 0);
-
-       wattrset(titlewin, COLOR_PAIR(COLOR_GREEN));
-       waddch(titlewin, ACS_VLINE);
-       wprintw(titlewin, "%s", "cg-view");
-       waddch(titlewin, ACS_LTEE);
-       whline(titlewin, ACS_HLINE, x);
-       wrefresh(titlewin);
-#endif
-       statuswin = newwin(1, 0, y - 1, 0);
-
-       wattrset(statuswin, COLOR_PAIR(COLOR_GREEN));
-       put_status(MSG_HELP);
-
-       mainwin = newwin(y - 1, 0, 0, 0);
-       scrollok(mainwin, TRUE);
-       keypad(mainwin, TRUE);  /* enable keyboard mapping */
 }
 
 /*
@@ -124,16 +159,11 @@ init(void)
  */
 
 #define DIFF_CMD       \
-       "git-rev-list HEAD^..HEAD | " \
-       "git-diff-tree --stdin --pretty -r --cc --always --stat"
-
-
-#define LOG_CMD0 \
-       "git-rev-list $(git-rev-parse --since=1.month) HEAD | " \
-       "git-diff-tree --stdin --pretty -r --root"
+       "git log --stat -n1 HEAD ; echo; " \
+       "git diff --find-copies-harder -B -C HEAD^ HEAD"
 
 #define LOG_CMD        \
-       "git-rev-list HEAD | git-diff-tree --stdin --pretty -r --root"
+       "git log --stat -n100"
 
 static void
 log_reader(char *line, int lineno)
@@ -141,75 +171,80 @@ log_reader(char *line, int lineno)
        static int log_reader_skip;
 
        if (!line) {
-               wattrset(mainwin, A_NORMAL);
+               wattrset(main_view.win, A_NORMAL);
                log_reader_skip = 0;
                return;
        }
 
        if (!strncmp("commit ", line, 7)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_GREEN));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_GREEN));
 
        } else if (!strncmp("Author: ", line, 8)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_CYAN));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_CYAN));
 
-       } else if (!strncmp("Date:   ", line, 6)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_YELLOW));
+       } else if (!strncmp("Date:   ", line, 8)) {
+               wattrset(main_view.win, COLOR_PAIR(COLOR_YELLOW));
 
        } else if (!strncmp("diff --git ", line, 11)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_YELLOW));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_YELLOW));
 
        } else if (!strncmp("diff-tree ", line, 10)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_BLUE));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_BLUE));
 
        } else if (!strncmp("index ", line, 6)) {
-               wattrset(mainwin, COLOR_PAIR(COLOR_BLUE));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_BLUE));
 
        } else if (line[0] == '-') {
-               wattrset(mainwin, COLOR_PAIR(COLOR_RED));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_RED));
 
        } else if (line[0] == '+') {
-               wattrset(mainwin, COLOR_PAIR(COLOR_GREEN));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_GREEN));
 
        } else if (line[0] == '@') {
-               wattrset(mainwin, COLOR_PAIR(COLOR_MAGENTA));
+               wattrset(main_view.win, COLOR_PAIR(COLOR_MAGENTA));
 
        } else if (line[0] == ':') {
-               pipe_lineno--;
+               main_view.lines--;
                log_reader_skip = 1;
                return;
 
        } else if (log_reader_skip) {
-               pipe_lineno--;
+               main_view.lines--;
                log_reader_skip = 0;
                return;
 
        } else {
-               wattrset(mainwin, A_NORMAL);
+               wattrset(main_view.win, A_NORMAL);
        }
 
-       mvwaddstr(mainwin, lineno, 0, line);
+       mvwaddstr(main_view.win, lineno, 0, line);
 }
 
-static FILE *
-open_pipe(char *cmd, pipe_reader_T reader)
+static struct view *
+update_view(struct view *view, char *cmd)
 {
-       pipe = popen(cmd, "r");
-       pipe_lineno = 0;
-       pipe_reader = reader;
-       wclear(mainwin);
-       wmove(mainwin, 0, 0);
+       view->cmd       = cmd;
+       view->pipe      = popen(cmd, "r");
+       view->lines     = 0;
+       view->lineno    = 0;
+       view->reader    = log_reader;
+
+       wclear(view->win);
+       wmove(view->win, 0, 0);
+
        put_status("Loading...");
-       return pipe;
+
+       return view;
 }
 
-static void
-read_pipe(int lines)
+static struct view *
+read_pipe(struct view *view, int lines)
 {
        char buffer[BUFSIZ];
        char *line;
        int x, y;
 
-       while ((line = fgets(buffer, sizeof(buffer), pipe))) {
+       while ((line = fgets(buffer, sizeof(buffer), view->pipe))) {
                int linelen;
 
                if (!--lines)
@@ -219,16 +254,23 @@ read_pipe(int lines)
                if (linelen)
                        line[linelen - 1] = 0;
 
-               pipe_reader(line, pipe_lineno++);
+               view->reader(line, view->lines++);
        }
 
-       if (feof(pipe) || ferror(pipe)) {
-               pipe_reader(NULL, pipe_lineno - 1);
-               pclose(pipe);
-               pipe = NULL;
-               pipe_reader = NULL;
-               put_status("%s (lines %d)", MSG_HELP, pipe_lineno - 1);
+       if (ferror(view->pipe)) {
+               put_status("Failed to read %s", view->cmd, view->lines - 1);
+
+       } else if (feof(view->pipe)) {
+               put_status("%s (lines %d)", MSG_HELP, view->lines - 1);
+
+       } else {
+               return view;
        }
+
+       view->reader(NULL, view->lines - 1);
+       pclose(view->pipe);
+       view->pipe = NULL;
+       view->reader = NULL;
 }
 
 /*
@@ -238,6 +280,8 @@ read_pipe(int lines)
 int
 main(int argc, char *argv[])
 {
+       static struct view *loading_view;
+
        init();
 
        //pipe = open_pipe(LOG_CMD, log_reader);
@@ -245,61 +289,113 @@ main(int argc, char *argv[])
        for (;;) {
                int c;
 
-               if (pipe) read_pipe(20);
-               if (pipe) nodelay(mainwin, TRUE);
+               if (do_resize) {
+                       resize_views();
+                       do_resize = 0;
+               }
+
+               if (loading_view && (loading_view = read_pipe(loading_view, 20)))
+                       nodelay(loading_view->win, TRUE);
 
-               c = wgetch(mainwin);     /* refresh, accept single keystroke of input */
+               c = wgetch(main_view.win);     /* refresh, accept single keystroke of input */
 
-               if (pipe) nodelay(mainwin, FALSE);
+               if (loading_view)
+                       nodelay(loading_view->win, FALSE);
 
                /* No input from wgetch() with nodelay() enabled. */
-               if (c == ERR)
+               if (c == ERR) {
+                       doupdate();
                        continue;
+               }
 
                /* Process the command keystroke */
                switch (c) {
+               case KEY_RESIZE:
+                       fprintf(stderr, "resize");
+                       exit;
+                       break;
+
                case KEY_ESC:
                case 'q':
                        quit(0);
+                       main_view.lineno--;
                        return 0;
 
                case KEY_DOWN:
                case 'j':
-                       wscrl(mainwin, 1);
+               {
+                       int x, y;
+
+                       getmaxyx(main_view.win, y, x);
+                       if (main_view.lineno + y < main_view.lines) {
+                               wscrl(main_view.win, 1);
+                               main_view.lineno++;
+                               put_status("line %d out of %d (%d%%)",
+                                          main_view.lineno,
+                                          main_view.lines,
+                                          100 * main_view.lineno / main_view.lines);
+                       } else {
+                               put_status("last line reached");
+                       }
                        break;
-
+               }
                case KEY_UP:
                case 'k':
-                       wscrl(mainwin, -1);
+                       if (main_view.lineno > 1) {
+                               wscrl(main_view.win, -1);
+                               main_view.lineno--;
+                               put_status("line %d out of %d (%d%%)",
+                                          main_view.lineno,
+                                          main_view.lines,
+                                          100 * main_view.lineno / main_view.lines);
+                       } else {
+                               put_status("first line reached");
+                       }
                        break;
 
                case 'c':
-                       wclear(mainwin);
+                       wclear(main_view.win);
                        break;
 
                case 'd':
-                       pipe = open_pipe(DIFF_CMD, log_reader);
+                       loading_view = update_view(&main_view, DIFF_CMD);
                        break;
 
                case 'l':
-                       pipe = open_pipe(LOG_CMD, log_reader);
+                       loading_view = update_view(&main_view, LOG_CMD);
                        break;
 
                case 's':
-                       mvwaddstr(statuswin, 0, 0, "Shelling out...");
+                       mvwaddstr(status_view.win, 0, 0, "Shelling out...");
                        def_prog_mode();           /* save current tty modes */
                        endwin();                  /* restore original tty modes */
                        system("sh");              /* run shell */
 
-                       werase(statuswin);
-                       mvwaddstr(statuswin, 0, 0, MSG_HELP);
+                       werase(status_view.win);
+                       mvwaddstr(status_view.win, 0, 0, MSG_HELP);
                        reset_prog_mode();
                        break;
                }
 
-               redrawwin(mainwin);
-               wrefresh(mainwin);
+               redrawwin(main_view.win);
+               wrefresh(main_view.win);
        }
 
        quit(0);
 }
+
+/**
+ * COPYRIGHT
+ * ---------
+ * Copyright (c) Jonas Fonseca, 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * SEE ALSO
+ * --------
+ * gitlink:cogito[7],
+ * gitlink:git[7]
+ **/