diff --git a/README.md b/README.md index 81c1223..e213764 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,51 @@ codegraph uninstall --- +## Language Support + +Every language below gets the same treatment — full structural extraction and cross-file resolution into one graph, no per-language setup: + +

+ TypeScript + JavaScript + ArkTS + Python + Go + Rust + Java + C# + PHP + Ruby + C + C++ + Objective-C + Metal + CUDA + Swift + Kotlin + Scala + Dart + Svelte + Vue + Astro + Liquid + Pascal / Delphi + Lua + R + Luau + CFML + COBOL + Visual Basic .NET + Erlang + Solidity + Terraform / OpenTofu + Nix +

+ +Per-language details — extensions, frameworks, and what exactly gets extracted — in [Supported Languages](#supported-languages). + +--- + ## Why CodeGraph? When an AI agent needs to understand code — to answer a question or make a change — it discovers structure the slow way: grep, glob, and Read, one file at a time, rebuilding call paths and dependencies by hand. That's a pile of tool calls and round-trips before it even starts the real work. diff --git a/assets/generate-language-tiles.py b/assets/generate-language-tiles.py new file mode 100644 index 0000000..0e78fb4 --- /dev/null +++ b/assets/generate-language-tiles.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +"""Generate assets/languages/*.svg — the README "Language Support" icon grid. + +One tile per supported language: a paper card with the language's vector mark and +its name centered underneath. Labels are converted to vector outlines (Archivo, +same pipeline as generate-waitlist.py) so the SVG renders pixel-identical +everywhere: GitHub loads README SVGs in "secure static mode", which blocks +@font-face / web-font loading, so outlines are the only reliable way to ship the +brand typeface. Every tile sits on the brand paper (#f7f6f2), so brand-colored +marks — including near-black ones like Rust — stay legible on GitHub light *and* +dark themes with no media-query tricks. + +Glyph sources (fetched at generation time, results checked in): + - simple-icons via https://cdn.simpleicons.org/ (CC0-1.0) + - devicon via jsDelivr, pinned @v2.16.0 (MIT) — Java, C#, + Objective-C, which simple-icons doesn't carry + - hand-drawn in this file: CFML, COBOL, VB.NET (no usable upstream mark) + +All trademarks/logos belong to their respective owners; they're used here only +to indicate language support. + +Adding a language: append to LANGS, re-run, reference the new SVG in README.md +with a fresh `?v=1`. If you change EXISTING tile bytes, bump that tile's `?v=N` +in README.md in the same commit (GitHub caches README images aggressively). + +Requires: fonttools, brotli (pip install fonttools brotli), network access. +Font: @fontsource-variable/archivo (latin, wght axis) from the landing-page package. +Usage: python3 generate-language-tiles.py [--preview /path/to/preview.svg] +""" +import os +import re +import sys +import urllib.request +from fontTools.ttLib import TTFont +from fontTools.varLib.instancer import instantiateVariableFont +from fontTools.pens.svgPathPen import SVGPathPen +from fontTools.pens.transformPen import TransformPen +from fontTools.misc.transform import Transform + +# --- brand palette (mirrors generate-waitlist.py) --------------------------- +PAPER = "#f7f6f2" +HAIRLINE = "#d6d3c8" +INK = "#16150f" + +FONT = os.path.join( + os.path.dirname(__file__), + "../../landing-page/node_modules/@fontsource-variable/archivo/files/archivo-latin-wght-normal.woff2", +) + +# --- tile geometry (px) ------------------------------------------------------ +TILE = 104 # square tile, rx=8 card like the waitlist button +GLYPH_BOX = 44 # logo box, horizontally centered +GLYPH_TOP = 18 +LABEL_SIZE = 12.5 +LABEL_WT = 640 +LABEL_GAP = 12 # glyph box bottom -> label cap top +TRACK = 0.15 + +DEVICON = "https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/{0}/{0}-{1}.svg" + +# (file slug, label, source) — README "Supported Languages" table order. +# source: ("si", slug) simple-icons | ("devicon", name, variant) | ("custom", key) +LANGS = [ + ("typescript", "TypeScript", ("si", "typescript")), + ("javascript", "JavaScript", ("si", "javascript")), + ("arkts", "ArkTS", ("si", "harmonyos")), + ("python", "Python", ("si", "python")), + ("go", "Go", ("si", "go")), + ("rust", "Rust", ("si", "rust")), + ("java", "Java", ("devicon", "java", "original")), + ("csharp", "C#", ("devicon", "csharp", "original")), + ("php", "PHP", ("si", "php")), + ("ruby", "Ruby", ("si", "ruby")), + ("c", "C", ("si", "c")), + ("cpp", "C++", ("si", "cplusplus")), + ("objective-c", "Objective-C", ("devicon", "objectivec", "plain")), + ("metal", "Metal", ("si", "apple")), + ("cuda", "CUDA", ("si", "nvidia")), + ("swift", "Swift", ("si", "swift")), + ("kotlin", "Kotlin", ("si", "kotlin")), + ("scala", "Scala", ("si", "scala")), + ("dart", "Dart", ("si", "dart")), + ("svelte", "Svelte", ("si", "svelte")), + ("vue", "Vue", ("si", "vuedotjs")), + ("astro", "Astro", ("si", "astro")), + ("liquid", "Liquid", ("si", "shopify")), + ("delphi", "Delphi", ("si", "delphi")), + ("lua", "Lua", ("si", "lua")), + ("r", "R", ("si", "r")), + ("luau", "Luau", ("si", "luau")), + ("cfml", "CFML", ("custom", "cfml")), + ("cobol", "COBOL", ("custom", "cobol")), + ("vbnet", "VB.NET", ("custom", "vbnet")), + ("erlang", "Erlang", ("si", "erlang")), + ("solidity", "Solidity", ("si", "solidity")), + ("terraform", "Terraform", ("si", "terraform")), + ("nix", "Nix", ("si", "nixos")), +] + + +def fetch(url): + req = urllib.request.Request(url, headers={"User-Agent": "codegraph-assets"}) + with urllib.request.urlopen(req, timeout=20) as r: + return r.read().decode("utf-8") + + +class Outliner: + """Archivo text -> SVG path outlines, one font instance per weight.""" + + def __init__(self): + self._by_weight = {} + + def _font(self, weight): + if weight not in self._by_weight: + ft = TTFont(FONT) + instantiateVariableFont(ft, {"wght": weight}, inplace=True) + self._by_weight[weight] = (ft, ft.getBestCmap(), ft.getGlyphSet(), ft["hmtx"]) + return self._by_weight[weight] + + def measure(self, text, size, weight, track=TRACK): + ft, cmap, _, hmtx = self._font(weight) + scale = size / ft["head"].unitsPerEm + w = sum(hmtx[cmap[ord(ch)]][0] * scale + track for ch in text) + return w - track + + def cap_height(self, size, weight): + ft, _, _, _ = self._font(weight) + return getattr(ft["OS/2"], "sCapHeight", 700) * size / ft["head"].unitsPerEm + + def outline(self, text, size, weight, start_x, baseline_y, track=TRACK): + ft, cmap, glyphs, hmtx = self._font(weight) + scale = size / ft["head"].unitsPerEm + sink = SVGPathPen(glyphs, ntos=lambda v: f"{round(v, 2):g}") + pen_x = start_x + for ch in text: + gname = cmap[ord(ch)] + if ch != " ": + t = Transform(scale, 0, 0, -scale, pen_x, baseline_y) + glyphs[gname].draw(TransformPen(sink, t)) + pen_x += hmtx[gname][0] * scale + track + return sink.getCommands() + + def centered(self, text, size, weight, center_x, baseline_y, track=TRACK): + w = self.measure(text, size, weight, track) + return self.outline(text, size, weight, center_x - w / 2, baseline_y, track) + + +def si_glyph(slug): + """simple-icons: single brand-colored 24x24 path, scaled into the glyph box.""" + svg = fetch(f"https://cdn.simpleicons.org/{slug}") + fill = re.search(r'fill="(#[0-9A-Fa-f]{3,8})"', svg).group(1) + d = re.search(r'' + + +def devicon_glyph(name, variant): + """devicon: multi-path 128x128 markup, embedded verbatim and scaled.""" + svg = fetch(DEVICON.format(name, variant)) + inner = re.search(r"]*>(.*)", svg, re.S).group(1).strip() + s = round(GLYPH_BOX / 128, 5) + x = (TILE - GLYPH_BOX) / 2 + return f'{inner}' + + +def custom_glyph(key, out): + x = (TILE - GLYPH_BOX) / 2 # glyph box left edge (30) + cx = TILE / 2 # 52 + cy = GLYPH_TOP + GLYPH_BOX / 2 # glyph box vertical center (40) + if key == "cfml": + # The community CFML mark: a tag, set in Archivo. + size, wt = 20.0, 700 + baseline = round(cy + out.cap_height(size, wt) / 2, 2) + d = out.centered("", size, wt, cx, baseline, track=0.4) + return f'' + if key == "cobol": + # A punched card: manila stock, clipped corner, punched rows. + w, h = GLYPH_BOX, 28 + top, cut = round(cy - h / 2, 2), 7 + holes = [] + for row in range(3): + hy = top + 7.4 + row * 6.4 + for col in range(7): + if (row * 3 + col * 5) % 4 != 0: # deterministic "data" pattern + holes.append( + f'' + ) + card = ( + f'M{x + cut},{top} H{x + w} V{top + h} H{x} V{top + cut} Z' + ) + return ( + f'' + + "".join(holes) + ) + if key == "vbnet": + # The .NET-purple badge with a VB monogram. + size, wt = 16.5, 720 + baseline = round(cy + out.cap_height(size, wt) / 2, 2) + d = out.centered("VB", size, wt, cx, baseline, track=0.6) + return ( + f'' + f'' + ) + raise KeyError(key) + + +def main(): + preview_path = None + if "--preview" in sys.argv: + preview_path = sys.argv[sys.argv.index("--preview") + 1] + + out = Outliner() + label_baseline = round(GLYPH_TOP + GLYPH_BOX + LABEL_GAP + out.cap_height(LABEL_SIZE, LABEL_WT), 2) + + out_dir = os.path.join(os.path.dirname(__file__), "languages") + os.makedirs(out_dir, exist_ok=True) + + bodies = {} + for slug, label, source in LANGS: + if source[0] == "si": + glyph = si_glyph(source[1]) + elif source[0] == "devicon": + glyph = devicon_glyph(source[1], source[2]) + else: + glyph = custom_glyph(source[1], out) + label_d = out.centered(label, LABEL_SIZE, LABEL_WT, TILE / 2, label_baseline) + body = ( + f'\n' + f" {glyph}\n" + f' ' + ) + bodies[slug] = body + svg = ( + f'\n' + f" {label}\n" + f" {body}\n" + f"\n" + ) + path = os.path.join(out_dir, f"{slug}.svg") + with open(path, "w") as fh: + fh.write(svg) + print(f"wrote {os.path.relpath(path, os.path.dirname(__file__))} ({len(svg)}b) {label}") + + if preview_path: + cols, pad = 7, 8 + rows = -(-len(LANGS) // cols) + w = cols * (TILE + pad) + pad + h = rows * (TILE + pad) + pad + cells = [] + for i, (slug, _, _) in enumerate(LANGS): + tx = pad + (i % cols) * (TILE + pad) + ty = pad + (i // cols) * (TILE + pad) + cells.append(f'{bodies[slug]}') + light = "".join(cells) + with open(preview_path, "w") as fh: + fh.write( + f'' + f'{light}' + f'{light}' + f"\n" + ) + print(f"wrote preview {preview_path} (top: light bg, bottom: dark bg)") + + +if __name__ == "__main__": + main() diff --git a/assets/languages/arkts.svg b/assets/languages/arkts.svg new file mode 100644 index 0000000..7510391 --- /dev/null +++ b/assets/languages/arkts.svg @@ -0,0 +1,6 @@ + + ArkTS + + + + diff --git a/assets/languages/astro.svg b/assets/languages/astro.svg new file mode 100644 index 0000000..78f10c1 --- /dev/null +++ b/assets/languages/astro.svg @@ -0,0 +1,6 @@ + + Astro + + + + diff --git a/assets/languages/c.svg b/assets/languages/c.svg new file mode 100644 index 0000000..dda6b43 --- /dev/null +++ b/assets/languages/c.svg @@ -0,0 +1,6 @@ + + C + + + + diff --git a/assets/languages/cfml.svg b/assets/languages/cfml.svg new file mode 100644 index 0000000..9c53f7d --- /dev/null +++ b/assets/languages/cfml.svg @@ -0,0 +1,6 @@ + + CFML + + + + diff --git a/assets/languages/cobol.svg b/assets/languages/cobol.svg new file mode 100644 index 0000000..7a67d90 --- /dev/null +++ b/assets/languages/cobol.svg @@ -0,0 +1,6 @@ + + COBOL + + + + diff --git a/assets/languages/cpp.svg b/assets/languages/cpp.svg new file mode 100644 index 0000000..8cdc15d --- /dev/null +++ b/assets/languages/cpp.svg @@ -0,0 +1,6 @@ + + C++ + + + + diff --git a/assets/languages/csharp.svg b/assets/languages/csharp.svg new file mode 100644 index 0000000..cb50063 --- /dev/null +++ b/assets/languages/csharp.svg @@ -0,0 +1,6 @@ + + C# + + + + diff --git a/assets/languages/cuda.svg b/assets/languages/cuda.svg new file mode 100644 index 0000000..c3c3d72 --- /dev/null +++ b/assets/languages/cuda.svg @@ -0,0 +1,6 @@ + + CUDA + + + + diff --git a/assets/languages/dart.svg b/assets/languages/dart.svg new file mode 100644 index 0000000..1256a56 --- /dev/null +++ b/assets/languages/dart.svg @@ -0,0 +1,6 @@ + + Dart + + + + diff --git a/assets/languages/delphi.svg b/assets/languages/delphi.svg new file mode 100644 index 0000000..402c2be --- /dev/null +++ b/assets/languages/delphi.svg @@ -0,0 +1,6 @@ + + Delphi + + + + diff --git a/assets/languages/erlang.svg b/assets/languages/erlang.svg new file mode 100644 index 0000000..9fd4fa5 --- /dev/null +++ b/assets/languages/erlang.svg @@ -0,0 +1,6 @@ + + Erlang + + + + diff --git a/assets/languages/go.svg b/assets/languages/go.svg new file mode 100644 index 0000000..3ce79e6 --- /dev/null +++ b/assets/languages/go.svg @@ -0,0 +1,6 @@ + + Go + + + + diff --git a/assets/languages/java.svg b/assets/languages/java.svg new file mode 100644 index 0000000..1fa0ca5 --- /dev/null +++ b/assets/languages/java.svg @@ -0,0 +1,6 @@ + + Java + + + + diff --git a/assets/languages/javascript.svg b/assets/languages/javascript.svg new file mode 100644 index 0000000..2303976 --- /dev/null +++ b/assets/languages/javascript.svg @@ -0,0 +1,6 @@ + + JavaScript + + + + diff --git a/assets/languages/kotlin.svg b/assets/languages/kotlin.svg new file mode 100644 index 0000000..b08f6ed --- /dev/null +++ b/assets/languages/kotlin.svg @@ -0,0 +1,6 @@ + + Kotlin + + + + diff --git a/assets/languages/liquid.svg b/assets/languages/liquid.svg new file mode 100644 index 0000000..bd87194 --- /dev/null +++ b/assets/languages/liquid.svg @@ -0,0 +1,6 @@ + + Liquid + + + + diff --git a/assets/languages/lua.svg b/assets/languages/lua.svg new file mode 100644 index 0000000..4e530e3 --- /dev/null +++ b/assets/languages/lua.svg @@ -0,0 +1,6 @@ + + Lua + + + + diff --git a/assets/languages/luau.svg b/assets/languages/luau.svg new file mode 100644 index 0000000..226b523 --- /dev/null +++ b/assets/languages/luau.svg @@ -0,0 +1,6 @@ + + Luau + + + + diff --git a/assets/languages/metal.svg b/assets/languages/metal.svg new file mode 100644 index 0000000..67d1149 --- /dev/null +++ b/assets/languages/metal.svg @@ -0,0 +1,6 @@ + + Metal + + + + diff --git a/assets/languages/nix.svg b/assets/languages/nix.svg new file mode 100644 index 0000000..28c0d67 --- /dev/null +++ b/assets/languages/nix.svg @@ -0,0 +1,6 @@ + + Nix + + + + diff --git a/assets/languages/objective-c.svg b/assets/languages/objective-c.svg new file mode 100644 index 0000000..2109863 --- /dev/null +++ b/assets/languages/objective-c.svg @@ -0,0 +1,6 @@ + + Objective-C + + + + diff --git a/assets/languages/php.svg b/assets/languages/php.svg new file mode 100644 index 0000000..509dcb3 --- /dev/null +++ b/assets/languages/php.svg @@ -0,0 +1,6 @@ + + PHP + + + + diff --git a/assets/languages/python.svg b/assets/languages/python.svg new file mode 100644 index 0000000..c3e160e --- /dev/null +++ b/assets/languages/python.svg @@ -0,0 +1,6 @@ + + Python + + + + diff --git a/assets/languages/r.svg b/assets/languages/r.svg new file mode 100644 index 0000000..2049b1d --- /dev/null +++ b/assets/languages/r.svg @@ -0,0 +1,6 @@ + + R + + + + diff --git a/assets/languages/ruby.svg b/assets/languages/ruby.svg new file mode 100644 index 0000000..caf752d --- /dev/null +++ b/assets/languages/ruby.svg @@ -0,0 +1,6 @@ + + Ruby + + + + diff --git a/assets/languages/rust.svg b/assets/languages/rust.svg new file mode 100644 index 0000000..af95860 --- /dev/null +++ b/assets/languages/rust.svg @@ -0,0 +1,6 @@ + + Rust + + + + diff --git a/assets/languages/scala.svg b/assets/languages/scala.svg new file mode 100644 index 0000000..9d9aa90 --- /dev/null +++ b/assets/languages/scala.svg @@ -0,0 +1,6 @@ + + Scala + + + + diff --git a/assets/languages/solidity.svg b/assets/languages/solidity.svg new file mode 100644 index 0000000..8767cc3 --- /dev/null +++ b/assets/languages/solidity.svg @@ -0,0 +1,6 @@ + + Solidity + + + + diff --git a/assets/languages/svelte.svg b/assets/languages/svelte.svg new file mode 100644 index 0000000..6be9944 --- /dev/null +++ b/assets/languages/svelte.svg @@ -0,0 +1,6 @@ + + Svelte + + + + diff --git a/assets/languages/swift.svg b/assets/languages/swift.svg new file mode 100644 index 0000000..b6aaab9 --- /dev/null +++ b/assets/languages/swift.svg @@ -0,0 +1,6 @@ + + Swift + + + + diff --git a/assets/languages/terraform.svg b/assets/languages/terraform.svg new file mode 100644 index 0000000..add5df7 --- /dev/null +++ b/assets/languages/terraform.svg @@ -0,0 +1,6 @@ + + Terraform + + + + diff --git a/assets/languages/typescript.svg b/assets/languages/typescript.svg new file mode 100644 index 0000000..9384ec8 --- /dev/null +++ b/assets/languages/typescript.svg @@ -0,0 +1,6 @@ + + TypeScript + + + + diff --git a/assets/languages/vbnet.svg b/assets/languages/vbnet.svg new file mode 100644 index 0000000..b3b052e --- /dev/null +++ b/assets/languages/vbnet.svg @@ -0,0 +1,6 @@ + + VB.NET + + + + diff --git a/assets/languages/vue.svg b/assets/languages/vue.svg new file mode 100644 index 0000000..0ede0ce --- /dev/null +++ b/assets/languages/vue.svg @@ -0,0 +1,6 @@ + + Vue + + + +