align widechars, optimize space a bit for 80x25, fix mailto: link - stagit-goph… | |
git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2h… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit e13c9e5eec3eca1670477033fa276e9b48e78f58 | |
parent e95a7d9de8805d9264b1d7cdcf43f15d2ec6b49c | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Wed, 14 Jun 2017 20:33:16 +0200 | |
align widechars, optimize space a bit for 80x25, fix mailto: link | |
Diffstat: | |
M TODO | 3 ++- | |
M stagit-index.c | 40 +++++++++++++++++++++++++++--… | |
M stagit.c | 56 +++++++++++++++++++++++------… | |
3 files changed, 79 insertions(+), 20 deletions(-) | |
--- | |
diff --git a/TODO b/TODO | |
@@ -1,6 +1,7 @@ | |
gopher: | |
-- align UTF-8 characters (and wide?). | |
+- cleanup code: escaping. | |
+? printutf8pad: print '...' when truncated? | |
- update documentation: | |
- document new gopher-specific options. | |
diff --git a/stagit-index.c b/stagit-index.c | |
@@ -8,6 +8,7 @@ | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
+#include <wchar.h> | |
#include <git2.h> | |
@@ -25,6 +26,31 @@ static char owner[255]; | |
#define pledge(p1,p2) 0 | |
#endif | |
+#define ISUTF8(c) (((c) & 0xc0) != 0x80) | |
+ | |
+/* print `len' columns of characters. If string is shorter pad the rest | |
+ * with characters `pad`. */ | |
+void | |
+printutf8pad(FILE *fp, const char *s, size_t len, int pad) | |
+{ | |
+ wchar_t w; | |
+ size_t n = 0, i; | |
+ int r; | |
+ | |
+ for (i = 0; *s && n < len; i++, s++) { | |
+ if (ISUTF8(*s)) { | |
+ if ((r = mbtowc(&w, s, 4)) == -1) | |
+ break; | |
+ if ((r = wcwidth(w)) == -1) | |
+ r = 1; | |
+ n += (size_t)r; | |
+ } | |
+ putc(*s, fp); | |
+ } | |
+ for (; n < len; n++) | |
+ putc(pad, fp); | |
+} | |
+ | |
void | |
trim(char *buf, size_t bufsiz, const char *src) | |
{ | |
@@ -87,9 +113,9 @@ writeheader(FILE *fp) | |
trim(buf, sizeof(buf), description); | |
if (buf[0] == 't') | |
fputc('t', fp); | |
- fprintf(fp, "%s\n", buf); | |
+ fprintf(fp, "%s\n\n", buf); | |
- fprintf(fp, "%-25.25s ", "Name"); | |
+ fprintf(fp, "%-20.20s ", "Name"); | |
fprintf(fp, "%-50.50s ", "Description"); | |
fprintf(fp, "%-25.25s ", "Owner"); | |
fprintf(fp, "%-16.16s\n", "Last commit"); | |
@@ -131,12 +157,16 @@ writelog(FILE *fp) | |
if (!strcmp(p, ".git")) | |
*p = '\0'; | |
+ fputs("[1|", fp); | |
trim(buf, sizeof(buf), stripped_name); | |
- fprintf(fp, "[1|%-25.25s ", buf); | |
+ printutf8pad(fp, buf, 20, ' '); | |
+ fputs(" ", fp); | |
trim(buf, sizeof(buf), description); | |
- fprintf(fp, "%-50.50s ", buf); | |
+ printutf8pad(fp, buf, 50, ' '); | |
+ fputs(" ", fp); | |
trim(buf, sizeof(buf), owner); | |
- fprintf(fp, "%-25.25s ", buf); | |
+ printutf8pad(fp, buf, 25, ' '); | |
+ fputs(" ", fp); | |
if (author) | |
printtimeshort(fp, &(author->when)); | |
trim(buf, sizeof(buf), stripped_name); | |
diff --git a/stagit.c b/stagit.c | |
@@ -9,6 +9,7 @@ | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
+#include <wchar.h> | |
#include <git2.h> | |
@@ -67,6 +68,31 @@ static const char *cachefile; | |
#define pledge(p1,p2) 0 | |
#endif | |
+#define ISUTF8(c) (((c) & 0xc0) != 0x80) | |
+ | |
+/* print `len' columns of characters. If string is shorter pad the rest | |
+ * with characters `pad`. */ | |
+void | |
+printutf8pad(FILE *fp, const char *s, size_t len, int pad) | |
+{ | |
+ wchar_t w; | |
+ size_t n = 0, i; | |
+ int r; | |
+ | |
+ for (i = 0; *s && n < len; i++, s++) { | |
+ if (ISUTF8(*s)) { | |
+ if ((r = mbtowc(&w, s, 4)) == -1) | |
+ break; | |
+ if ((r = wcwidth(w)) == -1) | |
+ r = 1; | |
+ n += (size_t)r; | |
+ } | |
+ putc(*s, fp); | |
+ } | |
+ for (; n < len; n++) | |
+ putc(pad, fp); | |
+} | |
+ | |
void | |
joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) | |
{ | |
@@ -420,7 +446,7 @@ writeheader(FILE *fp, const char *title) | |
fprintf(fp, "[1|README|%sfile/README.gph|server|port]\n", relp… | |
if (haslicense) | |
fprintf(fp, "[1|LICENSE|%sfile/LICENSE.gph|server|port]\n", re… | |
- fputs("===\n", fp); | |
+ fputs("---\n", fp); | |
} | |
void | |
@@ -432,7 +458,7 @@ int | |
writeblobgph(FILE *fp, const git_blob *blob) | |
{ | |
size_t n = 0, i, j, prev; | |
- const char *nfmt = "%8d "; | |
+ const char *nfmt = "%6d "; | |
const char *s = git_blob_rawcontent(blob); | |
git_off_t len = git_blob_rawsize(blob); | |
@@ -479,12 +505,11 @@ printcommit(FILE *fp, struct commitinfo *ci) | |
ci->parentoid, relpath, ci->parentoid); | |
if (ci->author) { | |
- /* TODO: fix author email link to redirect as mailto: */ | |
- fputs("[1|Author: ", fp); | |
+ fputs("[h|Author: ", fp); | |
gphlink(fp, ci->author->name, strlen(ci->author->name)); | |
fputs(" <", fp); | |
gphlink(fp, ci->author->email, strlen(ci->author->email)); | |
- fputs(">|mailto:", fp); | |
+ fputs(">|URL:mailto:", fp); | |
gphlink(fp, ci->author->email, strlen(ci->author->email)); | |
fputs("|server|port]\n", fp); | |
fputs("Date: ", fp); | |
@@ -556,7 +581,7 @@ printshowfile(FILE *fp, struct commitinfo *ci) | |
ci->addcount, ci->addcount == 1 ? "" : "s", | |
ci->delcount, ci->delcount == 1 ? "" : "s"); | |
- fputs("===\n", fp); | |
+ fputs("---\n", fp); | |
for (i = 0; i < ci->ndeltas; i++) { | |
patch = ci->deltas[i]->patch; | |
@@ -605,12 +630,12 @@ writelogline(FILE *fp, struct commitinfo *ci) | |
fputs(" ", fp); | |
if (ci->summary) { | |
trim(buf, sizeof(buf), ci->summary); | |
- fprintf(fp, "%-50.50s", buf); | |
+ printutf8pad(fp, buf, 50, ' '); | |
} | |
fputs(" ", fp); | |
if (ci->author) { | |
trim(buf, sizeof(buf), ci->author->name); | |
- fprintf(fp, "%-25.25s", buf); | |
+ printutf8pad(fp, buf, 25, ' '); | |
} | |
fprintf(fp, " %5zu", ci->filecount); | |
fprintf(fp, " %5zu+", ci->addcount); | |
@@ -766,7 +791,7 @@ writeblob(git_object *obj, const char *fpath, const char *f… | |
writeheader(fp, filename); | |
gphtext(fp, filename, strlen(filename)); | |
fprintf(fp, " (%juB)\n", (uintmax_t)filesize); | |
- fputs("===\n", fp); | |
+ fputs("---\n", fp); | |
if (git_blob_is_binary((git_blob *)obj)) { | |
fputs("Binary file.\n", fp); | |
@@ -872,7 +897,8 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) | |
fputs(filemode(git_tree_entry_filemode(entry)), fp); | |
fputs(" ", fp); | |
trim(buf, sizeof(buf), entrypath); | |
- fprintf(fp, "%-50.50s ", buf); | |
+ printutf8pad(fp, buf, 50, ' '); | |
+ fputs(" ", fp); | |
if (lc > 0) | |
fprintf(fp, "%7dL", lc); | |
else | |
@@ -882,7 +908,8 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) | |
git_object_free(obj); | |
} else if (!git_submodule_lookup(&module, repo, entryname)) { | |
fputs("[1|m--------- ", fp); | |
- gphlink(fp, entrypath, strlen(entrypath)); | |
+ trim(buf, sizeof(buf), entrypath); | |
+ printutf8pad(fp, buf, 50, ' '); | |
fprintf(fp, "|%sfile/.gitmodules.gph|server|port]\n", … | |
/* NOTE: linecount omitted */ | |
git_submodule_free(module); | |
@@ -983,7 +1010,7 @@ writerefs(FILE *fp) | |
/* print header if it has an entry (first). */ | |
if (++count == 1) { | |
fprintf(fp, "%s\n", titles[j]); | |
- fprintf(fp, " %-25.25s", "Name"); | |
+ fprintf(fp, " %-20.20s", "Name"); | |
fprintf(fp, " %-16.16s", "Last commit date"); | |
fprintf(fp, " %-25.25s\n", "Author"); | |
} | |
@@ -992,13 +1019,14 @@ writerefs(FILE *fp) | |
fputs(" ", fp); | |
trim(buf, sizeof(buf), name); | |
- fprintf(fp, "%-25.25s ", name); | |
+ printutf8pad(fp, buf, 20, ' '); | |
+ fputs(" ", fp); | |
if (ci->author) | |
printtimeshort(fp, &(ci->author->when)); | |
fputs(" ", fp); | |
if (ci->author) { | |
trim(buf, sizeof(buf), ci->author->name); | |
- fprintf(fp, "%-25.25s\n", buf); | |
+ printutf8pad(fp, buf, 25, ' '); | |
} | |
fputs("\n", fp); | |