char/sorcery
static-files based git repo viewer
git clone https://git.t4t.associates/char/sorcery
ceba7fd
main
1use std:: collections:: BTreeMap ; 2 3use anyhow:: Result ; 4 5# [ derive ( Clone , Copy )] 6pub ( crate ) struct Stat { 7/// grammar id (after grouping); what the client filters on 8pub id : &' static str , 9pub name : &' static str , 10pub color : &' static str , 11pub bytes : u64 , 12} 13 14pub ( crate ) fn analyze ( repo : & gix:: Repository , tree : & gix:: Tree < ' _ >) ->Result < Vec < Stat >> { 15fn walk ( 16repo : & gix:: Repository , 17tree : & gix:: Tree < ' _ >, 18bytes : & mut BTreeMap < &' static str , u64 >, 19) ->Result <()> { 20for entryin tree. iter () { 21let entry = entry?; 22let mode = entry. mode (); 23let filename = entry. filename (). to_string (); 24if mode. is_tree () { 25if !excluded_directory ( & filename) { 26walk ( repo, & repo. find_object ( entry. oid ()) ?. try_into_tree () ?, bytes) ?; 27} 28} else if !mode. is_link () 29 && !mode. is_commit () 30 && !excluded_file ( & filename) 31 &&let Some ( language) =crate :: grammar_manifest:: detect ( & filename) 32{ 33let size = repo. find_header ( entry. oid ()) ?. size () as u64 ; 34* bytes. entry ( group ( language)). or_default () += size; 35} 36} 37Ok (()) 38} 39 40let mut bytes =BTreeMap :: new (); 41walk ( repo, tree, & mut bytes) ?; 42let mut stats = bytes 43. into_iter () 44. map ( |( language, bytes) |{ 45let ( name, color) =metadata ( language); 46Stat { id : language, name, color, bytes} 47}) 48. collect ::< Vec < _ >>(); 49 stats. sort_by ( |a, b| b. bytes . cmp ( & a. bytes ). then_with ( || a. name . cmp ( b. name ))); 50Ok ( stats) 51} 52 53// mirrored by looksGenerated in web/util.ts; keep them in sync 54fn excluded_directory ( name : & str ) ->bool { 55[ 56"node_modules" , 57"vendor" , 58"third_party" , 59"third-party" , 60"target" , 61"dist" , 62"build" , 63"coverage" , 64".next" , 65".nuxt" , 66".output" , 67".yarn" , 68".gradle" , 69".terraform" , 70".dart_tool" , 71".direnv" , 72".venv" , 73"venv" , 74"__pycache__" , 75"Pods" , 76"Carthage" , 77"generated" , 78] 79. iter () 80. any ( |excluded| name. eq_ignore_ascii_case ( excluded)) 81} 82 83fn excluded_file ( name : & str ) ->bool { 84if [ 85"Cargo.lock" , 86"package-lock.json" , 87"npm-shrinkwrap.json" , 88"yarn.lock" , 89"pnpm-lock.yaml" , 90"bun.lock" , 91"bun.lockb" , 92"deno.lock" , 93"composer.lock" , 94"Gemfile.lock" , 95"go.sum" , 96"poetry.lock" , 97"uv.lock" , 98"Pipfile.lock" , 99"pdm.lock" , 100"flake.lock" , 101"mix.lock" , 102"pubspec.lock" , 103"Package.resolved" , 104"packages.lock.json" , 105"gradle.lockfile" , 106"Podfile.lock" , 107"Cartfile.resolved" , 108] 109. iter () 110. any ( |excluded| name. eq_ignore_ascii_case ( excluded)) 111{ 112return true ; 113} 114 115let name = name. to_ascii_lowercase (); 116 name. ends_with ( ".lock" ) 117 || name. ends_with ( ".min.js" ) 118 || name. ends_with ( ".min.css" ) 119 || name. contains ( ".generated." ) 120 || name. contains ( "_generated." ) 121 || name. ends_with ( ".g.dart" ) 122 || name. ends_with ( ".pb.go" ) 123 || name. ends_with ( ".pb.rs" ) 124 || name. ends_with ( ".pb.cc" ) 125 || name. ends_with ( ".pb.h" ) 126 || name. ends_with ( "_pb2.py" ) 127 || name. ends_with ( ".designer.cs" ) 128} 129 130// mirrored by languageGroup in web/languages.ts; keep them in sync 131fn group ( language : &' static str ) ->&' static str { 132match language{ 133"tsx" =>"typescript" , 134 _ => language, 135} 136} 137 138fn metadata ( language : &' static str ) ->( &' static str , &' static str ) { 139match language{ 140"ada" =>( "Ada" , "#02f88c" ), 141"agda" =>( "Agda" , "#315665" ), 142"asciidoc" =>( "AsciiDoc" , "#73a0c5" ), 143"asm" |"x86asm" =>( "Assembly" , "#6e4c13" ), 144"awk" =>( "Awk" , "#c30e9b" ), 145"bash" |"zsh" =>( "Shell" , "#89e051" ), 146"batch" =>( "Batchfile" , "#c1f12e" ), 147"c" =>( "C" , "#555555" ), 148"c-sharp" =>( "C#" , "#7355dd" ), 149"caddy" =>( "Caddyfile" , "#22b638" ), 150"capnp" =>( "Cap'n Proto" , "#c42727" ), 151"cedar" =>( "Cedar" , "#958792" ), 152"cedarschema" =>( "Cedar Schema" , "#958792" ), 153"clojure" =>( "Clojure" , "#db5855" ), 154"cmake" =>( "CMake" , "#da3434" ), 155"cobol" =>( "COBOL" , "#958792" ), 156"commonlisp" =>( "Common Lisp" , "#3fb68b" ), 157"cpp" =>( "C++" , "#f34b7d" ), 158"css" =>( "CSS" , "#663399" ), 159"d" =>( "D" , "#ba595e" ), 160"dart" =>( "Dart" , "#00b4ab" ), 161"devicetree" =>( "Device Tree" , "#958792" ), 162"diff" =>( "Diff" , "#958792" ), 163"dockerfile" =>( "Dockerfile" , "#384d54" ), 164"dot" =>( "Graphviz (DOT)" , "#2596be" ), 165"elisp" =>( "Emacs Lisp" , "#c065db" ), 166"elixir" =>( "Elixir" , "#6e4a7e" ), 167"elm" =>( "Elm" , "#60b5cc" ), 168"erlang" =>( "Erlang" , "#b83998" ), 169"fish" =>( "fish" , "#4aae47" ), 170"fsharp" =>( "F#" , "#b845fc" ), 171"gitattributes" =>( "Git Attributes" , "#f44d27" ), 172"gleam" =>( "Gleam" , "#ffaff3" ), 173"glsl" =>( "GLSL" , "#5686a5" ), 174"go" =>( "Go" , "#00add8" ), 175"graphql" =>( "GraphQL" , "#e10098" ), 176"groovy" =>( "Groovy" , "#4298b8" ), 177"haskell" =>( "Haskell" , "#5e5086" ), 178"hcl" =>( "HCL" , "#844fba" ), 179"hlsl" =>( "HLSL" , "#aace60" ), 180"html" =>( "HTML" , "#e34c26" ), 181"idris" =>( "Idris" , "#b30000" ), 182"ini" =>( "INI" , "#d1dbe0" ), 183"java" =>( "Java" , "#b07219" ), 184"javascript" =>( "JavaScript" , "#f1e05a" ), 185"jinja2" =>( "Jinja" , "#a52a22" ), 186"jq" =>( "jq" , "#c7254e" ), 187"jsdoc" =>( "JSDoc" , "#958792" ), 188"json" =>( "JSON" , "#292929" ), 189"julia" =>( "Julia" , "#a270ba" ), 190"just" =>( "Just" , "#384d54" ), 191"kconfig" =>( "Kconfig" , "#958792" ), 192"kdl" =>( "KDL" , "#ffb3b3" ), 193"kotlin" =>( "Kotlin" , "#a97bff" ), 194"lean" =>( "Lean" , "#958792" ), 195"lua" =>( "Lua" , "#000080" ), 196"make" =>( "Makefile" , "#427819" ), 197"markdown" =>( "Markdown" , "#083fa1" ), 198"matlab" =>( "MATLAB" , "#e16737" ), 199"meson" =>( "Meson" , "#007800" ), 200"nginx" =>( "Nginx" , "#009639" ), 201"ninja" =>( "Ninja" , "#958792" ), 202"nix" =>( "Nix" , "#7e7eff" ), 203"objc" =>( "Objective-C" , "#438eff" ), 204"ocaml" =>( "OCaml" , "#ef7a08" ), 205"odin" =>( "Odin" , "#60affe" ), 206"perl" =>( "Perl" , "#0298c3" ), 207"php" =>( "PHP" , "#4f5d95" ), 208"postscript" =>( "PostScript" , "#da291c" ), 209"powershell" =>( "PowerShell" , "#012456" ), 210"prolog" =>( "Prolog" , "#74283c" ), 211"proto" =>( "Protocol Buffer" , "#958792" ), 212"python" =>( "Python" , "#3572a5" ), 213"query" =>( "Tree-sitter Query" , "#8ea64c" ), 214"r" =>( "R" , "#198ce7" ), 215"regex" =>( "Regular Expression" , "#009a00" ), 216"rego" =>( "Open Policy Agent" , "#7d9199" ), 217"rescript" =>( "ReScript" , "#ed5051" ), 218"ron" =>( "RON" , "#a62c00" ), 219"ruby" =>( "Ruby" , "#701516" ), 220"rust" =>( "Rust" , "#dea584" ), 221"scala" =>( "Scala" , "#c22d40" ), 222"scheme" =>( "Scheme" , "#1e4aec" ), 223"scss" =>( "SCSS" , "#c6538c" ), 224"solidity" =>( "Solidity" , "#aa6746" ), 225"sparql" =>( "SPARQL" , "#0c4597" ), 226"sql" =>( "SQL" , "#e38c00" ), 227"ssh-config" =>( "SSH Config" , "#958792" ), 228"starlark" =>( "Starlark" , "#76d275" ), 229"styx" =>( "Styx" , "#958792" ), 230"svelte" =>( "Svelte" , "#ff3e00" ), 231"swift" =>( "Swift" , "#f05138" ), 232"textproto" =>( "Protocol Buffer Text Format" , "#958792" ), 233"thrift" =>( "Thrift" , "#d12127" ), 234"tlaplus" =>( "TLA" , "#4b0079" ), 235"toml" =>( "TOML" , "#9c4221" ), 236"typescript" =>( "TypeScript" , "#3178c6" ), 237"typst" =>( "Typst" , "#239dad" ), 238"uiua" =>( "Uiua" , "#958792" ), 239"vb" =>( "Visual Basic .NET" , "#945db7" ), 240"verilog" =>( "Verilog" , "#b2b7f8" ), 241"vhdl" =>( "VHDL" , "#adb2cb" ), 242"vim" =>( "Vim script" , "#199f4b" ), 243"vue" =>( "Vue" , "#41b883" ), 244"wit" =>( "WebAssembly Interface Type" , "#6250e7" ), 245"xml" =>( "XML" , "#0060ac" ), 246"yaml" =>( "YAML" , "#cb171e" ), 247"yuri" =>( "Yuri" , "#958792" ), 248"zig" =>( "Zig" , "#ec915c" ), 249 _ =>( language, "#958792" ), 250} 251} 252 253# [ cfg ( test )] 254mod tests{ 255use super :: excluded_file; 256 257# [ test ] 258fn generated_file_patterns_do_not_overreach () { 259for namein [ "schema.generated.ts" , "messages.pb.go" , "app.min.js" , "CARGO.LOCK" ] { 260assert! ( excluded_file ( name), "expected {name} to be excluded" ); 261} 262for namein [ "Cargo.toml" , "pnpm-workspace.yaml" , "src.rs" , "generator.ts" ] { 263assert! ( !excluded_file ( name), "expected {name} to be retained" ); 264} 265} 266}