Repositories / gitweb2.git
gitweb2.git
Clone (read-only): git clone http://git.guha-anderson.com/git/gitweb2.git
@@ -8,6 +8,7 @@ (depends (ocaml (>= 5.4)) dune + ppx_format ocaml-git cohttp-eio eio_main
@@ -4,6 +4,7 @@ synopsis: "Read-only local Git web viewer" depends: [ "ocaml" {>= "5.4"} "dune" {>= "3.22"} + "ppx_format" "ocaml-git" "cohttp-eio" "eio_main"
@@ -2,7 +2,9 @@ (name gitweb2) (public_name gitweb2) (modules gitweb2) - (libraries ocaml-git unix uri cohttp-eio eio_main)) + (libraries ocaml-git unix uri cohttp-eio eio_main) + (preprocess + (pps ppx_format))) (executable (name main)
@@ -111,11 +111,12 @@ let file_render ?(pygments_command : string = default_pygments_command) ~(file_p let is_readme (name : string) : bool = name = "README.md" || name = "README.txt" || name = "README" let page (title : string) (body : string) : string = - "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n\ - <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>" - ^ html title - ^ " · gitweb2</title>\n<style>\n\ - :root { color-scheme: light; --ink: #1f2428; --muted: #586069; --line: #d0d7de; --wash: #f6f8fa; --link: #0969da; --accent: #1a7f37; }\n\ + let buffer = Buffer.create (String.length body + 4096) in + Buffer.add_string buffer "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n\ + <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>"; + Printf.bprintf buffer [%i "{%s html title} · gitweb2</title>\n<style>\n"]; + Buffer.add_string buffer + ":root { color-scheme: light; --ink: #1f2428; --muted: #586069; --line: #d0d7de; --wash: #f6f8fa; --link: #0969da; --accent: #1a7f37; }\n\ * { box-sizing: border-box; }\n\ body { margin: 0; font: 15px/1.5 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; color: var(--ink); background: #fff; }\n\ a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; }\n\ @@ -140,8 +141,10 @@ let page (title : string) (body : string) : string = .readme { margin-top: 24px; } .file-meta { padding: 10px 12px; border-bottom: 1px solid var(--line); background: #fff; }\n\ .notice { padding: 16px; border: 1px solid var(--line); border-radius: 8px; background: var(--wash); }\n\ @media (max-width: 640px) { main { padding: 20px 12px 40px; } h1 { font-size: 23px; } .kind { width: 78px; } }\n\ - </style>\n</head>\n<body><main>" - ^ body ^ "</main></body>\n</html>" + </style>\n</head>\n<body><main>"; + Buffer.add_string buffer body; + Buffer.add_string buffer "</main></body>\n</html>"; + Buffer.contents buffer let normalize_root (root : string) : string = let expanded = @@ -216,22 +219,23 @@ let entries_for_display (entries : Ocaml_git.tree_entry list) : Ocaml_git.tree_e let repo_header (repo : repo_info) (branch : string) (path : string) (branches : Ocaml_git.branch list) (selected : string) : string = let buffer = Buffer.create 512 in - Buffer.add_string buffer ("<section class=\"repo-head\"><p><a href=\"/\">Repositories</a> / " ^ html repo.name ^ "</p>"); - Buffer.add_string buffer ("<h1>" ^ html (if path = "" then repo.name else path) ^ "</h1>"); - Buffer.add_string buffer "<div class=\"toolbar\"><span>Branch</span><nav>"; + let heading_title = if String.length path = 0 then repo.name else path in + Printf.bprintf buffer + [%i + {|<section class="repo-head"><p><a href="/">Repositories</a> / {%s html repo.name}</p><h1>{%s html heading_title}</h1><div class="toolbar"><span>Branch</span><nav>|} ]; List.iter (fun (item : Ocaml_git.branch) -> let active = if item.name = branch then " class=\"active\"" else "" in - Buffer.add_string buffer ("<a" ^ active ^ " href=\"" ^ repo_url repo item.name path ^ "\">" ^ html item.name ^ "</a>")) + Printf.bprintf buffer [%i {|<a{%s active} href="{%s repo_url repo item.name path}">{%s html item.name}</a>|} ]) branches; - Buffer.add_string buffer "</nav></div><div class=\"tabs\">"; + Printf.bprintf buffer [%i {|</nav></div><div class="tabs">|} ]; let tab id label href = let active = if id = selected then " class=\"active\"" else "" in - Buffer.add_string buffer ("<a" ^ active ^ " href=\"" ^ href ^ "\">" ^ label ^ "</a>") + Printf.bprintf buffer [%i {|<a{%s active} href="{%s href}">{%s label}</a>|} ] in tab "code" "Code" (repo_url repo branch path); tab "history" "History" ("/repo/" ^ url_encode repo.key ^ "/" ^ url_encode branch ^ "/-/commits"); - Buffer.add_string buffer "</div></section>"; + Printf.bprintf buffer [%i {|</div></section>|} ]; Buffer.contents buffer let tree_view ~(pygments_command : string) (repo : repo_info) (git : Ocaml_git.t) (branch : string) (path : string) @@ -240,31 +244,29 @@ let tree_view ~(pygments_command : string) (repo : repo_info) (git : Ocaml_git.t let listing = Ocaml_git.tree ~commit ~path git () in let buffer = Buffer.create 4096 in Buffer.add_string buffer (repo_header repo branch path branches "code"); - Buffer.add_string buffer "<div class=\"panel\"><table><tbody>"; - if path <> "" then ( + Printf.bprintf buffer [%i {|<div class="panel"><table><tbody>|} ]; + if String.length path <> 0 then ( let parent = try Filename.dirname path with _ -> "" in let parent = if parent = "." then "" else parent in - Buffer.add_string buffer ("<tr><td><a href=\"" ^ repo_url repo branch parent ^ "\">..</a></td><td class=\"kind\">tree</td></tr>") - ) else (); + Printf.bprintf buffer [%i {|<tr><td><a href="{%s repo_url repo branch parent}">..</a></td><td class="kind">tree</td></tr>|} ]) + else (); let display_entries = entries_for_display listing.entries in List.iter (fun (entry : Ocaml_git.tree_entry) -> let child = join_path path entry.name in - Buffer.add_string buffer ("<tr><td><a href=\"" ^ repo_url repo branch child ^ "\">" ^ html entry.name ^ "</a></td>"); let kind = match entry.kind with Blob -> "blob" | Tree -> "tree" | Commit -> "commit" | Tag -> "tag" | Other -> "other" in - Buffer.add_string buffer ("<td class=\"kind\">" ^ kind ^ "</td></tr>")) + Printf.bprintf buffer [%i {|<tr><td><a href="{%s repo_url repo branch child}">{%s html entry.name}</a></td><td class="kind">{%s kind}</td></tr>|} ]) display_entries; - Buffer.add_string buffer "</tbody></table></div>"; + Printf.bprintf buffer [%i {|</tbody></table></div>|} ]; (match List.find_opt (fun (entry : Ocaml_git.tree_entry) -> is_readme entry.name && entry.kind = Blob) display_entries with | None -> () | Some readme -> let readme_path = join_path path readme.name in let blob = Ocaml_git.blob ~commit git readme_path in if not (Ocaml_git.blob_is_binary blob) then ( - Buffer.add_string buffer "<section class=\"readme\">"; - Buffer.add_string buffer ("<h2>" ^ html readme.name ^ "</h2><div class=\"panel file\">"); + Printf.bprintf buffer [%i {|<section class="readme"><h2>{%s html readme.name}</h2><div class="panel file">|} ]; Buffer.add_string buffer (file_render ~pygments_command ~file_path:(join_path repo.path readme_path) (Ocaml_git.blob_text blob)); Buffer.add_string buffer "</div></section>") else ()); @@ -274,10 +276,7 @@ let blob_view ~(pygments_command : string) (repo : repo_info) (blob : Ocaml_git. (branches : Ocaml_git.branch list) : string = let buffer = Buffer.create 4096 in Buffer.add_string buffer (repo_header repo branch path branches "code"); - Buffer.add_string buffer "<div class=\"panel file\">"; - Buffer.add_string buffer - ("<div class=\"file-meta\">" ^ string_of_int (String.length blob.Ocaml_git.bytes) ^ " bytes · " - ^ html (String.sub blob.id 0 (min 12 (String.length blob.id))) ^ "</div>"); + Printf.bprintf buffer [%i {|<div class="panel file"><div class="file-meta">{%d String.length blob.Ocaml_git.bytes} bytes · {%s html (String.sub blob.id 0 (min 12 (String.length blob.id)))}</div>|} ]; if Ocaml_git.blob_is_binary blob then Buffer.add_string buffer "<p class=\"notice\">Binary file</p>" else Buffer.add_string buffer (file_render ~pygments_command ~file_path:(join_path repo.path path) (Ocaml_git.blob_text blob)); Buffer.add_string buffer "</div>"; @@ -287,15 +286,12 @@ let commits_page (repo : repo_info) (branch : string) : string = Ocaml_git.with_repo repo.path @@ fun git -> let buffer = Buffer.create 4096 in Buffer.add_string buffer (repo_header repo branch "" (local_branches git) "history"); - Buffer.add_string buffer "<ol class=\"commits\">"; + Printf.bprintf buffer [%i {|<ol class="commits">|} ]; List.iter (fun (commit : Ocaml_git.commit) -> - Buffer.add_string buffer - ("<li><strong>" ^ html commit.summary ^ "</strong><span>" - ^ html (String.sub commit.id 0 (min 12 (String.length commit.id))) - ^ " · " ^ html commit.author.name ^ "</span></li>")) + Printf.bprintf buffer [%i {|<li><strong>{%s html commit.summary}</strong><span>{%s html (String.sub commit.id 0 (min 12 (String.length commit.id)))} · {%s html commit.author.name}</span></li>|} ]) (Ocaml_git.commits ~limit:100 git branch); - Buffer.add_string buffer "</ol>"; + Printf.bprintf buffer [%i {|</ol>|} ]; page (branch ^ " history") (Buffer.contents buffer) let repo_page ~(pygments_command : string) (repo : repo_info) (branch : string) (path : string) : string = @@ -322,17 +318,16 @@ let route ?(pygments_command : string = default_pygments_command) ~(root : strin match parts with | [] -> let buffer = Buffer.create 4096 in - Buffer.add_string buffer ("<section class=\"hero\"><p class=\"eyebrow\">" ^ html root ^ "</p><h1>Repositories</h1></section>"); + Printf.bprintf buffer [%i {|<section class="hero"><p class="eyebrow">{%s html root}</p><h1>Repositories</h1></section>|} ]; if repos = [] then Buffer.add_string buffer "<p class=\"notice\">No Git repositories were found under this path.</p>" else ( Buffer.add_string buffer "<ol class=\"repo-list\">"; List.iter (fun repo -> let summary = repo_summary repo in - Buffer.add_string buffer ("<li><a href=\"" ^ repo_url repo summary.branch "" ^ "\"><strong>" ^ html repo.name ^ "</strong>"); - Buffer.add_string buffer ("<span>" ^ html summary.branch); - if summary.short_id <> "" then Buffer.add_string buffer (" · " ^ html summary.short_id); - Buffer.add_string buffer ("</span><small>" ^ html summary.summary ^ "</small></a></li>")) + Printf.bprintf buffer [%i {|<li><a href="{%s repo_url repo summary.branch ""}"><strong>{%s html repo.name}</strong><span>{%s html summary.branch}|} ]; + if String.length summary.short_id <> 0 then Printf.bprintf buffer [%i {| · {%s html summary.short_id}|} ]; + Printf.bprintf buffer [%i {|</span><small>{%s html summary.summary}</small></a></li>|} ]) repos; Buffer.add_string buffer "</ol>"); { status = 200; body = page "Repositories" (Buffer.contents buffer) }