stagit

Personal Stagit Fork
commit 1a1d986a920a2ddd56e8db4c0ed039a50e8277b5
parent deb822c63f0298af256d313754b7d81bec708ab5
Author: maydayv7 <maydayv7@gmail.com>
Date:   Sun,  4 Jan 2026 00:47:25 +0530

refactor: Use `render.py`

Diffstat:
MREADME.md | 3+--
Mflake.nix | 37++++++++++++++++++++++++-------------
Arender.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstagit.c | 111+++++++++++++++++++++++++++-----------------------------------------------------
4 files changed, 117 insertions(+), 89 deletions(-)

diff --git a/README.md b/README.md @@ -11,10 +11,9 @@ This is my personal [fork](https://git.codemadness.org/stagit/) of `stagit`. - Modified styling - Added `-n` flag to set `sitename` for header button - Pages are now styled by the `style.css` present at root -- Added [md4c](https://github.com/mity/md4c) to parse Markdown files -- Added [Chroma](https://github.com/alecthomas/chroma) for code syntax highlighting - Sort repositories by last commit time on `index` page - Use local system timezone +- Added code syntax highlighting and Markdown rendering using [`render.py`](./render.py) ## Usage diff --git a/flake.nix b/flake.nix @@ -8,35 +8,46 @@ outputs = { nixpkgs, utils, ... }: utils.lib.eachDefaultSystem ( - system: with nixpkgs.legacyPackages.${system}; { - packages.default = stdenv.mkDerivation { + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + pythonEnv = pkgs.python3.withPackages ( + ps: with ps; [ + pygments + markdown + pymdown-extensions + ] + ); + in + { + packages.default = pkgs.stdenv.mkDerivation { pname = "stagit"; version = "1.2-custom"; src = ./.; - - buildInputs = [ - libgit2 - md4c - ]; - + buildInputs = [ pkgs.libgit2 ]; nativeBuildInputs = [ - pkg-config - makeWrapper + pkgs.pkg-config + pkgs.makeWrapper ]; buildPhase = '' make PREFIX=$out \ - STAGIT_CFLAGS="-I${libgit2}/include -I${md4c}/include" \ - STAGIT_LDFLAGS="-L${libgit2}/lib -lgit2 -L${md4c}/lib -lmd4c -lmd4c-html" + STAGIT_CFLAGS="-I${pkgs.libgit2}/include" \ + STAGIT_LDFLAGS="-L${pkgs.libgit2}/lib -lgit2" ''; installPhase = '' mkdir -p $out/bin mkdir -p $out/share/doc/stagit + cp stagit $out/bin/ cp stagit-index $out/bin/ cp favicon.png $out/share/doc/stagit/ - wrapProgram $out/bin/stagit --prefix PATH : ${lib.makeBinPath [ chroma ]} + + cp render.py $out/bin/render + sed -i "1i #!${pythonEnv}/bin/python3" $out/bin/render + chmod +x $out/bin/render + wrapProgram $out/bin/stagit --prefix PATH : "$out/bin" ''; }; } diff --git a/render.py b/render.py @@ -0,0 +1,55 @@ +import pygments +from pygments import highlight +from pygments.formatters import HtmlFormatter +from pygments.lexers import guess_lexer, guess_lexer_for_filename +from sys import stdin, stderr + +filename = stdin.readline().strip() +contents = stdin.read() +lexer = None + +try: + lexer = guess_lexer_for_filename(filename, contents) +except pygments.util.ClassNotFound: + try: + lexer = guess_lexer(contents) + except pygments.util.ClassNotFound: + pass + +if lexer is None: + from pygments.lexers import TextLexer + + lexer = TextLexer() + +rendered = None +if lexer.__class__ is pygments.lexers.MarkdownLexer: + from markdown import markdown + + rendered = markdown( + contents, + extensions=["codehilite", "extra", "sane_lists", "smarty", "pymdownx.tasklist"], + ) + +FORMAT = HtmlFormatter( + style="murphy", + cssclass="highlight", + linenos="table", + lineanchors="loc", + anchorlinenos=True, + linespans="line", +) + +if rendered: + print("<h3>Rendered</h3>") + print('<article class="markup markdown">') + print(rendered) + print("</article>") + print("<br /><h3>Code</h3>") + +print('<div id="blob">') +print(highlight(contents, lexer, FORMAT)) +print("</div>") + +print("Filename: {}; Lexer: {}.".format(filename, lexer), file=stderr) +if rendered: + print("Markdown was rendered in addition.", file=stderr) diff --git a/stagit.c b/stagit.c @@ -16,7 +16,6 @@ #include "compat.h" -#include <md4c-html.h> #define CMD_BUFSIZE 255 #define LEN(s) (sizeof(s) / sizeof(*s)) @@ -533,7 +532,7 @@ void writeheader(FILE *fp, const char *title) { fputs("</div>\n", fp); fputs("</div>\n", fp); - fputs("<nav class=\"menu-desktop\">\n", fp); + fputs("<nav class=\"menu\">\n", fp); fputs("<ul class=\"menu-inner\">\n", fp); fprintf(fp, "<li><a href=\"%slog.html\">Log</a></li>", relpath); @@ -587,92 +586,58 @@ const char *get_ext(const char *filename) { return dot + 1; } -void processmd(const char *output, unsigned int len, void *fp) { - fprintf((FILE *)fp, "%.*s", len, output); -} - -size_t writeblobmd(FILE *fp, const git_blob *blob) { - size_t n = 0, i, len, prev, ret; - const char *s = git_blob_rawcontent(blob); - len = git_blob_rawsize(blob); - fputs("<div id=\"md\">\n", fp); +int custom_render(const char *filename, FILE *fp, const char *s, size_t len) { + fflush(fp); - if (len > 0) { - for (i = 0, prev = 0; i < len; i++) { - if (s[i] != '\n') - continue; - n++; - prev = i + 1; - } - if ((len - prev) > 0) - n++; - - ret = md_html(s, len, processmd, fp, - MD_FLAG_TABLES | MD_FLAG_TASKLISTS | - MD_FLAG_PERMISSIVEEMAILAUTOLINKS | - MD_FLAG_PERMISSIVEURLAUTOLINKS, - 0); + int stdout_copy = dup(1); + if (stdout_copy == -1) { + fprintf(stderr, "Error duplicating stdout: %s\n", strerror(errno)); + return 0; } - fputs("</div>\n", fp); - return n; -} -size_t writeblobhtml(const char *filename, FILE *fp, const git_blob *blob) { - char *line = NULL; - size_t linesize = 0; - ssize_t linelen; - int lineno = 1; - char tmp_path[] = "/tmp/stagit-blob-XXXXXX"; - int fd; - FILE *chroma_out; - char cmd[1024]; - - const char *content = git_blob_rawcontent(blob); - size_t content_len = git_blob_rawsize(blob); - - if ((fd = mkstemp(tmp_path)) == -1) { - fprintf(stderr, "stagit: mkstemp failed\n"); + if (dup2(fileno(fp), 1) == -1) { + fprintf(stderr, "Error redirecting stdout: %s\n", strerror(errno)); + close(stdout_copy); return 0; } - if (write(fd, content, content_len) == -1) { - fprintf(stderr, "stagit: write to temp failed\n"); - close(fd); - unlink(tmp_path); + + FILE *child = popen("render", "w"); + if (child == NULL) { + dup2(stdout_copy, 1); + close(stdout_copy); + fprintf(stderr, "popen('render') failed: %s\n", strerror(errno)); return 0; } - close(fd); - snprintf(cmd, sizeof(cmd), - "chroma --html --html-only --html-prevent-surrounding-pre " - "--filename '%s' %s", - filename, tmp_path); + fprintf(child, "%s\n", filename); - chroma_out = popen(cmd, "r"); - if (!chroma_out) { - unlink(tmp_path); - return 0; + size_t i; + int lc = 0; + for (i = 0; *s && i < len; s++, i++) { + if (*s == '\n') + lc++; + fputc(*s, child); } - fputs("<table id=\"blob\" class=\"chroma\"><tbody>\n", fp); + pclose(child); - while ((linelen = getline(&line, &linesize, chroma_out)) != -1) { - if (line[linelen - 1] == '\n') - line[linelen - 1] = '\0'; + fflush(stdout); - fprintf(fp, - "<tr><td class=\"num\"><a href=\"#l%d\" id=\"l%d\">%d</a></td>" - "<td class=\"code\">%s</td></tr>\n", - lineno, lineno, lineno, line); - lineno++; - } + dup2(stdout_copy, 1); + close(stdout_copy); - fputs("</tbody></table>\n", fp); + return lc; +} + +int writeblobhtml(const char *filename, FILE *fp, const git_blob *blob) { + int lc = 0; + const char *s = git_blob_rawcontent(blob); + git_off_t len = git_blob_rawsize(blob); - free(line); - pclose(chroma_out); - unlink(tmp_path); + if (len > 0) + lc = custom_render(filename, fp, s, len); - return lineno - 1; + return lc; } void printcommit(FILE *fp, struct commitinfo *ci) { @@ -1070,8 +1035,6 @@ size_t writeblob(git_object *obj, const char *fpath, const char *filename, if (git_blob_is_binary((git_blob *)obj)) fputs("<p>Binary file.</p>\n", fp); - else if (git_blob_is_markdown_file(filename)) - lc = writeblobmd(fp, (git_blob *)obj); else lc = writeblobhtml(filename, fp, (git_blob *)obj);