commit eabec8e6a5d4972d0135e39b4730551b6399473a
parent 96cbcdf6e6f2e5e572c8b01a6990151462cb4b00
Author: gracefu <81774659+gracefuu@users.noreply.github.com>
Date: Sat, 3 May 2025 00:47:18 +0800
Allow overriding the style file
Diffstat:
| M | stagit-index.c | | | 361 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
| M | stagit.c | | | 342 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
2 files changed, 386 insertions(+), 317 deletions(-)
diff --git a/stagit-index.c b/stagit-index.c
@@ -16,6 +16,165 @@ static char description[255] = "Repositories";
static char *name = "";
static char owner[255];
+static char * const default_style =
+ "body {\n"
+ " color: #000;\n"
+ " background-color: #fff;\n"
+ " font-family: monospace;\n"
+ "}\n"
+ "\n"
+ "h1, h2, h3, h4, h5, h6 {\n"
+ " font-size: 1em;\n"
+ " margin: 0;\n"
+ "}\n"
+ "\n"
+ "img, svg, h1, h2 {\n"
+ " vertical-align: middle;\n"
+ "}\n"
+ "\n"
+ "img {\n"
+ " border: 0;\n"
+ "}\n"
+ "\n"
+ "a:target {\n"
+ " background-color: #ccc;\n"
+ "}\n"
+ "\n"
+ "a.d,\n"
+ "a.h,\n"
+ "a.i,\n"
+ "a.line {\n"
+ " text-decoration: none;\n"
+ "}\n"
+ "\n"
+ "#blob a {\n"
+ " color: #555;\n"
+ "}\n"
+ " \n"
+ "#blob a:hover {\n"
+ " color: blue;\n"
+ " text-decoration: none;\n"
+ "}\n"
+ " \n"
+ "table thead td {\n"
+ " font-weight: bold;\n"
+ "}\n"
+ "\n"
+ "table td {\n"
+ " padding: 0 0.4em;\n"
+ "}\n"
+ "\n"
+ "#content table td {\n"
+ " vertical-align: top;\n"
+ " white-space: nowrap;\n"
+ "}\n"
+ " \n"
+ "#branches tr:hover td,\n"
+ "#tags tr:hover td,\n"
+ "#index tr:hover td,\n"
+ "#log tr:hover td,\n"
+ "#files tr:hover td {\n"
+ " background-color: #eee;\n"
+ "}\n"
+ " \n"
+ "#index tr td:nth-child(2),\n"
+ "#tags tr td:nth-child(3),\n"
+ "#branches tr td:nth-child(3),\n"
+ "#log tr td:nth-child(2) {\n"
+ " white-space: normal;\n"
+ "}\n"
+ " \n"
+ "td.num {\n"
+ " text-align: right;\n"
+ "}\n"
+ " \n"
+ ".desc {\n"
+ " color: #555;\n"
+ "}\n"
+ "\n"
+ "hr {\n"
+ " border: 0;\n"
+ " border-top: 1px solid #555;\n"
+ " height: 1px;\n"
+ "}\n"
+ "\n"
+ "pre {\n"
+ " font-family: monospace;\n"
+ "}\n"
+ "\n"
+ "pre a.h {\n"
+ " color: #00a;\n"
+ "}\n"
+ "\n"
+ ".A,\n"
+ "span.i,\n"
+ "pre a.i {\n"
+ " color: #070;\n"
+ "}\n"
+ "\n"
+ ".D,\n"
+ "span.d,\n"
+ "pre a.d {\n"
+ " color: #e00;\n"
+ "}\n"
+ "\n"
+ "pre a.h:hover,\n"
+ "pre a.i:hover,\n"
+ "pre a.d:hover {\n"
+ " text-decoration: none;\n"
+ "}\n"
+ "\n"
+ "@media (prefers-color-scheme: dark) {\n"
+ " body {\n"
+ " background-color: #000;\n"
+ " color: #bdbdbd;\n"
+ " }\n"
+ " hr {\n"
+ " border-color: #222;\n"
+ " }\n"
+ " a {\n"
+ " color: #56c8ff;\n"
+ " }\n"
+ " a:target {\n"
+ " background-color: #222;\n"
+ " }\n"
+ " .desc {\n"
+ " color: #aaa;\n"
+ " }\n"
+ " #blob a {\n"
+ " color: #555;\n"
+ " }\n"
+ " #blob a:target {\n"
+ " color: #eee;\n"
+ " }\n"
+ " #blob a:hover {\n"
+ " color: #56c8ff;\n"
+ " }\n"
+ " pre a.h {\n"
+ " color: #00cdcd;\n"
+ " }\n"
+ " .A,\n"
+ " span.i,\n"
+ " pre a.i {\n"
+ " color: #00cd00;\n"
+ " }\n"
+ " .D,\n"
+ " span.d,\n"
+ " pre a.d {\n"
+ " color: #cd0000;\n"
+ " }\n"
+ " #branches tr:hover td,\n"
+ " #tags tr:hover td,\n"
+ " #index tr:hover td,\n"
+ " #log tr:hover td,\n"
+ " #files tr:hover td {\n"
+ " background-color: #111;\n"
+ " }\n"
+ "}\n";
+
+static char *stylefile;
+static char *style = default_style;
+
/* Handle read or write errors for a FILE * stream */
void
checkfileerror(FILE *fp, const char *name, int mode)
@@ -112,163 +271,9 @@ writeheader(FILE *fp)
"<meta name=\"msapplication-TileColor\" content=\"#603cba\">\n"
"<meta name=\"msapplication-config\" content=\"/icons/browserconfig.xml\">\n"
"<meta name=\"theme-color\" content=\"#ffffff\">\n");
- fprintf(fp,
- "<style>\n"
- "body {\n"
- " color: #000;\n"
- " background-color: #fff;\n"
- " font-family: monospace;\n"
- "}\n"
- "\n"
- "h1, h2, h3, h4, h5, h6 {\n"
- " font-size: 1em;\n"
- " margin: 0;\n"
- "}\n"
- "\n"
- "img, svg, h1, h2 {\n"
- " vertical-align: middle;\n"
- "}\n"
- "\n"
- "img {\n"
- " border: 0;\n"
- "}\n"
- "\n"
- "a:target {\n"
- " background-color: #ccc;\n"
- "}\n"
- "\n"
- "a.d,\n"
- "a.h,\n"
- "a.i,\n"
- "a.line {\n"
- " text-decoration: none;\n"
- "}\n"
- "\n"
- "#blob a {\n"
- " color: #555;\n"
- "}\n"
- " \n"
- "#blob a:hover {\n"
- " color: blue;\n"
- " text-decoration: none;\n"
- "}\n"
- " \n"
- "table thead td {\n"
- " font-weight: bold;\n"
- "}\n"
- "\n"
- "table td {\n"
- " padding: 0 0.4em;\n"
- "}\n"
- "\n"
- "#content table td {\n"
- " vertical-align: top;\n"
- " white-space: nowrap;\n"
- "}\n"
- " \n"
- "#branches tr:hover td,\n"
- "#tags tr:hover td,\n"
- "#index tr:hover td,\n"
- "#log tr:hover td,\n"
- "#files tr:hover td {\n"
- " background-color: #eee;\n"
- "}\n"
- " \n"
- "#index tr td:nth-child(2),\n"
- "#tags tr td:nth-child(3),\n"
- "#branches tr td:nth-child(3),\n"
- "#log tr td:nth-child(2) {\n"
- " white-space: normal;\n"
- "}\n"
- " \n"
- "td.num {\n"
- " text-align: right;\n"
- "}\n"
- " \n"
- ".desc {\n"
- " color: #555;\n"
- "}\n"
- "\n"
- "hr {\n"
- " border: 0;\n"
- " border-top: 1px solid #555;\n"
- " height: 1px;\n"
- "}\n"
- "\n"
- "pre {\n"
- " font-family: monospace;\n"
- "}\n"
- "\n"
- "pre a.h {\n"
- " color: #00a;\n"
- "}\n"
- "\n"
- ".A,\n"
- "span.i,\n"
- "pre a.i {\n"
- " color: #070;\n"
- "}\n"
- "\n"
- ".D,\n"
- "span.d,\n"
- "pre a.d {\n"
- " color: #e00;\n"
- "}\n"
- "\n"
- "pre a.h:hover,\n"
- "pre a.i:hover,\n"
- "pre a.d:hover {\n"
- " text-decoration: none;\n"
- "}\n"
- "\n"
- "@media (prefers-color-scheme: dark) {\n"
- " body {\n"
- " background-color: #000;\n"
- " color: #bdbdbd;\n"
- " }\n"
- " hr {\n"
- " border-color: #222;\n"
- " }\n"
- " a {\n"
- " color: #56c8ff;\n"
- " }\n"
- " a:target {\n"
- " background-color: #222;\n"
- " }\n"
- " .desc {\n"
- " color: #aaa;\n"
- " }\n"
- " #blob a {\n"
- " color: #555;\n"
- " }\n"
- " #blob a:target {\n"
- " color: #eee;\n"
- " }\n"
- " #blob a:hover {\n"
- " color: #56c8ff;\n"
- " }\n"
- " pre a.h {\n"
- " color: #00cdcd;\n"
- " }\n"
- " .A,\n"
- " span.i,\n"
- " pre a.i {\n"
- " color: #00cd00;\n"
- " }\n"
- " .D,\n"
- " span.d,\n"
- " pre a.d {\n"
- " color: #cd0000;\n"
- " }\n"
- " #branches tr:hover td,\n"
- " #tags tr:hover td,\n"
- " #index tr:hover td,\n"
- " #log tr:hover td,\n"
- " #files tr:hover td {\n"
- " background-color: #111;\n"
- " }\n"
- "}\n"
- "</style>\n");
+ fputs("<style>\n", fp);
+ fputs(style, fp);
+ fputs("</style>\n", fp);
fputs("</head>\n<body>\n", fp);
fprintf(fp, "<table>\n<tr><td><a href=\"../\"><svg height=\"32px\" width=\"32px\" xmlns=\"http://www.w3.org/2000/svg\"><circle r=\"16\" cx=\"16\" cy=\"16\" fill=\"lightpink\"></circle></svg></a></td>\n"
"<td><span class=\"desc\">");
@@ -339,13 +344,13 @@ err:
int
main(int argc, char *argv[])
{
- FILE *fp;
+ FILE *fp, *fpread;
char path[PATH_MAX], repodirabs[PATH_MAX + 1];
const char *repodir;
int i, ret = 0;
if (argc < 2) {
- fprintf(stderr, "usage: %s [repodir...]\n", argv[0]);
+ fprintf(stderr, "usage: %s [-s stylefile] [repodir...]\n", argv[0]);
return 1;
}
@@ -362,9 +367,47 @@ main(int argc, char *argv[])
err(1, "pledge");
#endif
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ continue;
+ }
+ if (argv[i][1] == 's') {
+ if (i + 1 >= argc)
+ fprintf(stderr, "usage: %s [-s stylefile] [repodir...]\n", argv[0]);
+ stylefile = argv[++i];
+ continue;
+ }
+ err(1, "usage: %s [-s stylefile] [repodir...]\n", argv[0]);
+ }
+
+ if (stylefile) {
+ if (!(fpread = fopen(stylefile, "r")))
+ err(1, "fopen: '%s'", stylefile);
+
+ if (fpread) {
+ fseek(fpread, 0, SEEK_END);
+ long int len = ftell(fpread);
+ rewind(fpread);
+ if (len >= 0) {
+ style = calloc(1, (size_t)len + 1);
+ if (!fread(style, (size_t)len, 1, fpread)) {
+ free(style);
+ style = default_style;
+ }
+ }
+ checkfileerror(fpread, stylefile, 'r');
+ fclose(fpread);
+ }
+ }
+
writeheader(stdout);
for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ ++i;
+ continue;
+ }
+
repodir = argv[i];
if (!realpath(repodir, repodirabs))
err(1, "realpath");
diff --git a/stagit.c b/stagit.c
@@ -73,6 +73,164 @@ static char *readmefiles[] = { "HEAD:README", "HEAD:README.md" };
static char *readme;
static long long nlogcommits = -1; /* -1 indicates not used */
+static char * const default_style =
+ "body {\n"
+ " color: #000;\n"
+ " background-color: #fff;\n"
+ " font-family: monospace;\n"
+ "}\n"
+ "\n"
+ "h1, h2, h3, h4, h5, h6 {\n"
+ " font-size: 1em;\n"
+ " margin: 0;\n"
+ "}\n"
+ "\n"
+ "img, svg, h1, h2 {\n"
+ " vertical-align: middle;\n"
+ "}\n"
+ "\n"
+ "img {\n"
+ " border: 0;\n"
+ "}\n"
+ "\n"
+ "a:target {\n"
+ " background-color: #ccc;\n"
+ "}\n"
+ "\n"
+ "a.d,\n"
+ "a.h,\n"
+ "a.i,\n"
+ "a.line {\n"
+ " text-decoration: none;\n"
+ "}\n"
+ "\n"
+ "#blob a {\n"
+ " color: #555;\n"
+ "}\n"
+ " \n"
+ "#blob a:hover {\n"
+ " color: blue;\n"
+ " text-decoration: none;\n"
+ "}\n"
+ " \n"
+ "table thead td {\n"
+ " font-weight: bold;\n"
+ "}\n"
+ "\n"
+ "table td {\n"
+ " padding: 0 0.4em;\n"
+ "}\n"
+ "\n"
+ "#content table td {\n"
+ " vertical-align: top;\n"
+ " white-space: nowrap;\n"
+ "}\n"
+ " \n"
+ "#branches tr:hover td,\n"
+ "#tags tr:hover td,\n"
+ "#index tr:hover td,\n"
+ "#log tr:hover td,\n"
+ "#files tr:hover td {\n"
+ " background-color: #eee;\n"
+ "}\n"
+ " \n"
+ "#index tr td:nth-child(2),\n"
+ "#tags tr td:nth-child(3),\n"
+ "#branches tr td:nth-child(3),\n"
+ "#log tr td:nth-child(2) {\n"
+ " white-space: normal;\n"
+ "}\n"
+ " \n"
+ "td.num {\n"
+ " text-align: right;\n"
+ "}\n"
+ " \n"
+ ".desc {\n"
+ " color: #555;\n"
+ "}\n"
+ "\n"
+ "hr {\n"
+ " border: 0;\n"
+ " border-top: 1px solid #555;\n"
+ " height: 1px;\n"
+ "}\n"
+ "\n"
+ "pre {\n"
+ " font-family: monospace;\n"
+ "}\n"
+ "\n"
+ "pre a.h {\n"
+ " color: #00a;\n"
+ "}\n"
+ "\n"
+ ".A,\n"
+ "span.i,\n"
+ "pre a.i {\n"
+ " color: #070;\n"
+ "}\n"
+ "\n"
+ ".D,\n"
+ "span.d,\n"
+ "pre a.d {\n"
+ " color: #e00;\n"
+ "}\n"
+ "\n"
+ "pre a.h:hover,\n"
+ "pre a.i:hover,\n"
+ "pre a.d:hover {\n"
+ " text-decoration: none;\n"
+ "}\n"
+ "\n"
+ "@media (prefers-color-scheme: dark) {\n"
+ " body {\n"
+ " background-color: #000;\n"
+ " color: #bdbdbd;\n"
+ " }\n"
+ " hr {\n"
+ " border-color: #222;\n"
+ " }\n"
+ " a {\n"
+ " color: #56c8ff;\n"
+ " }\n"
+ " a:target {\n"
+ " background-color: #222;\n"
+ " }\n"
+ " .desc {\n"
+ " color: #aaa;\n"
+ " }\n"
+ " #blob a {\n"
+ " color: #555;\n"
+ " }\n"
+ " #blob a:target {\n"
+ " color: #eee;\n"
+ " }\n"
+ " #blob a:hover {\n"
+ " color: #56c8ff;\n"
+ " }\n"
+ " pre a.h {\n"
+ " color: #00cdcd;\n"
+ " }\n"
+ " .A,\n"
+ " span.i,\n"
+ " pre a.i {\n"
+ " color: #00cd00;\n"
+ " }\n"
+ " .D,\n"
+ " span.d,\n"
+ " pre a.d {\n"
+ " color: #cd0000;\n"
+ " }\n"
+ " #branches tr:hover td,\n"
+ " #tags tr:hover td,\n"
+ " #index tr:hover td,\n"
+ " #log tr:hover td,\n"
+ " #files tr:hover td {\n"
+ " background-color: #111;\n"
+ " }\n"
+ "}\n";
+static char *stylefile;
+static char *style = default_style;
+
/* cache */
static git_oid lastoid;
static char lastoidstr[GIT_OID_HEXSZ + 2]; /* id + newline + NUL byte */
@@ -528,163 +686,9 @@ writeheader(FILE *fp, const char *title)
fputs("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"", fp);
xmlencode(fp, name, strlen(name));
fprintf(fp, " Atom Feed (tags)\" href=\"%stags.xml\" />\n", relpath);
- fprintf(fp,
- "<style>\n"
- "body {\n"
- " color: #000;\n"
- " background-color: #fff;\n"
- " font-family: monospace;\n"
- "}\n"
- "\n"
- "h1, h2, h3, h4, h5, h6 {\n"
- " font-size: 1em;\n"
- " margin: 0;\n"
- "}\n"
- "\n"
- "img, svg, h1, h2 {\n"
- " vertical-align: middle;\n"
- "}\n"
- "\n"
- "img {\n"
- " border: 0;\n"
- "}\n"
- "\n"
- "a:target {\n"
- " background-color: #ccc;\n"
- "}\n"
- "\n"
- "a.d,\n"
- "a.h,\n"
- "a.i,\n"
- "a.line {\n"
- " text-decoration: none;\n"
- "}\n"
- "\n"
- "#blob a {\n"
- " color: #555;\n"
- "}\n"
- " \n"
- "#blob a:hover {\n"
- " color: blue;\n"
- " text-decoration: none;\n"
- "}\n"
- " \n"
- "table thead td {\n"
- " font-weight: bold;\n"
- "}\n"
- "\n"
- "table td {\n"
- " padding: 0 0.4em;\n"
- "}\n"
- "\n"
- "#content table td {\n"
- " vertical-align: top;\n"
- " white-space: nowrap;\n"
- "}\n"
- " \n"
- "#branches tr:hover td,\n"
- "#tags tr:hover td,\n"
- "#index tr:hover td,\n"
- "#log tr:hover td,\n"
- "#files tr:hover td {\n"
- " background-color: #eee;\n"
- "}\n"
- " \n"
- "#index tr td:nth-child(2),\n"
- "#tags tr td:nth-child(3),\n"
- "#branches tr td:nth-child(3),\n"
- "#log tr td:nth-child(2) {\n"
- " white-space: normal;\n"
- "}\n"
- " \n"
- "td.num {\n"
- " text-align: right;\n"
- "}\n"
- " \n"
- ".desc {\n"
- " color: #555;\n"
- "}\n"
- "\n"
- "hr {\n"
- " border: 0;\n"
- " border-top: 1px solid #555;\n"
- " height: 1px;\n"
- "}\n"
- "\n"
- "pre {\n"
- " font-family: monospace;\n"
- "}\n"
- "\n"
- "pre a.h {\n"
- " color: #00a;\n"
- "}\n"
- "\n"
- ".A,\n"
- "span.i,\n"
- "pre a.i {\n"
- " color: #070;\n"
- "}\n"
- "\n"
- ".D,\n"
- "span.d,\n"
- "pre a.d {\n"
- " color: #e00;\n"
- "}\n"
- "\n"
- "pre a.h:hover,\n"
- "pre a.i:hover,\n"
- "pre a.d:hover {\n"
- " text-decoration: none;\n"
- "}\n"
- "\n"
- "@media (prefers-color-scheme: dark) {\n"
- " body {\n"
- " background-color: #000;\n"
- " color: #bdbdbd;\n"
- " }\n"
- " hr {\n"
- " border-color: #222;\n"
- " }\n"
- " a {\n"
- " color: #56c8ff;\n"
- " }\n"
- " a:target {\n"
- " background-color: #222;\n"
- " }\n"
- " .desc {\n"
- " color: #aaa;\n"
- " }\n"
- " #blob a {\n"
- " color: #555;\n"
- " }\n"
- " #blob a:target {\n"
- " color: #eee;\n"
- " }\n"
- " #blob a:hover {\n"
- " color: #56c8ff;\n"
- " }\n"
- " pre a.h {\n"
- " color: #00cdcd;\n"
- " }\n"
- " .A,\n"
- " span.i,\n"
- " pre a.i {\n"
- " color: #00cd00;\n"
- " }\n"
- " .D,\n"
- " span.d,\n"
- " pre a.d {\n"
- " color: #cd0000;\n"
- " }\n"
- " #branches tr:hover td,\n"
- " #tags tr:hover td,\n"
- " #index tr:hover td,\n"
- " #log tr:hover td,\n"
- " #files tr:hover td {\n"
- " background-color: #111;\n"
- " }\n"
- "}\n"
- "</style>\n");
+ fputs("<style>\n", fp);
+ fputs(style, fp);
+ fputs("</style>\n", fp);
fputs("</head>\n<body>\n<table><tr><td>", fp);
fprintf(fp, "<a href=\"../%s\"><svg height=\"32px\" width=\"32px\" xmlns=\"http://www.w3.org/2000/svg\"><circle r=\"16\" cx=\"16\" cy=\"16\" fill=\"lightpink\"></circle></svg></a>", relpath);
fputs("</td><td><h1>", fp);
@@ -1350,7 +1354,7 @@ void
usage(char *argv0)
{
fprintf(stderr, "usage: %s [-c cachefile | -l commits] "
- "[-u baseurl] repodir\n", argv0);
+ "[-u baseurl] [-s stylefile] repodir\n", argv0);
exit(1);
}
@@ -1387,6 +1391,10 @@ main(int argc, char *argv[])
if (i + 1 >= argc)
usage(argv[0]);
baseurl = argv[++i];
+ } else if (argv[i][1] == 's') {
+ if (i + 1 >= argc)
+ usage(argv[0]);
+ stylefile = argv[++i];
}
}
if (!repodir)
@@ -1395,6 +1403,24 @@ main(int argc, char *argv[])
if (!realpath(repodir, repodirabs))
err(1, "realpath");
+ if (stylefile) {
+ fpread = efopen(stylefile, "r");
+ if (fpread) {
+ fseek(fpread, 0, SEEK_END);
+ long int len = ftell(fpread);
+ rewind(fpread);
+ if (len >= 0) {
+ style = calloc(1, (size_t)len + 1);
+ if (!fread(style, (size_t)len, 1, fpread)) {
+ free(style);
+ style = default_style;
+ }
+ }
+ checkfileerror(fpread, stylefile, 'r');
+ fclose(fpread);
+ }
+ }
+
/* do not search outside the git repository:
GIT_CONFIG_LEVEL_APP is the highest level currently */
git_libgit2_init();