#lang racket/base (require net/sendurl racket/list json xml racket/string "config.rkt" "utils.rkt" ) (provide diff->html show->html config-diff2html ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Helper functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (make-js . args) (string-join args "\n")) (define (highlight-css) (cfg-get 'diff 'highlight-css "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css") ) (define (diff2html-min-css) (cfg-get 'diff 'diff2html-min-css "https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css") ) (define (diff2html-ui-min-js) (cfg-get 'diff 'diff2html-ui-min-js "https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js") ) (define (diff-script diff) (format (make-js "window.do_diff = function() {" "const diff = ~a;" "const ui = new Diff2HtmlUI(" " document.getElementById('diff')," " diff," " {" " drawFileList: true," " matching: 'lines'," " outputFormat: 'side-by-side'," " });" "ui.draw();" "ui.highlightCode();" "};" ) (jsexpr->string diff)) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Exported functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (config-diff2html) (define (checker f) (λ (inp) (let ((url (string-trim inp))) (if (string=? url "") (f) (if (valid-http-or-file-url? url) url (begin (displayln "! Not a valid url, please input a valid url") #f))))) ) (define (inp name f) (input-prompt (string-join (list (format "Give the url for the ~a" name) "Enter keeps the current value:" (string-append " - " (f)) ">") "\n") #:loop-until (checker f))) (let ((h-css (inp "Highlighting CSS" highlight-css)) (d-css (inp "Diff2Html CSS" diff2html-min-css)) (d-js (inp "Diff2Html UI Javascript" diff2html-ui-min-js)) ) (cfg-set! 'diff 'highlight-css h-css) (cfg-set! 'diff 'diff2html-min-css d-css) (cfg-set! 'diff 'diff2html-ui-min-js d-js)) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : Render a Git diff in a temporary HTML file. ; pre : diff is a unified Git diff string. ; post : The generated HTML file has been opened in the default browser. ; result : void. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (diff->html diff) (let ((html `(html (head (meta ((charset "utf-8"))) (link ((rel "stylesheet") (href ,(highlight-css)))) (link ((rel "stylesheet") (href ,(diff2html-min-css)))) (script ((src ,(diff2html-ui-min-js))) "") (script ,(diff-script diff)) ) (body (div ((id "diff"))) (script ((type "text/javascript")) "window.do_diff();") )))) (let ((tmp-file (build-path (find-system-path 'temp-dir) "racket-git-diff.html"))) (call-with-output-file tmp-file #:exists 'truncate (λ (out) (display (xexpr->string html) out))) (send-url/file tmp-file)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : Render git show output as commit information followed by a diff. ; pre : show is the textual output produced by git show. ; post : The generated HTML file has been opened in the default browser. ; result : void. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (show->html show) (let* ((lines (string-split show "\n" #:trim? #f)) (diff-pos (let loop ((rest lines) (n 0)) (cond ((null? rest) #f) ((string-prefix? (car rest) "diff --git ") n) (else (loop (cdr rest) (+ n 1)))))) (header (string-join (if diff-pos (take lines diff-pos) lines) "\n")) (diff (string-join (if diff-pos (drop lines diff-pos) '()) "\n")) (html `(html (head (meta ((charset "utf-8"))) (link ((rel "stylesheet") (href ,(highlight-css)))) (link ((rel "stylesheet") (href ,(diff2html-min-css)))) (style "body { font-family: sans-serif; margin: 1.5em; } pre.commit { white-space: pre-wrap; }") ,@(if diff-pos `((script ((src ,(diff2html-ui-min-js))) "") (script ,(diff-script diff))) '()) ) (body (pre ((class "commit")) ,header) ,@(if diff-pos `((div ((id "diff"))) (script ((type "text/javascript")) "window.do_diff();")) '()) )))) (let ((tmp-file (build-path (find-system-path 'temp-dir) "racket-git-show.html"))) (call-with-output-file tmp-file #:exists 'truncate (λ (out) (display (xexpr->string html) out))) (send-url/file tmp-file))))