pyvegh 0.7.0__cp310-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyvegh-0.7.0.dist-info/METADATA +241 -0
- pyvegh-0.7.0.dist-info/RECORD +9 -0
- pyvegh-0.7.0.dist-info/WHEEL +4 -0
- pyvegh-0.7.0.dist-info/entry_points.txt +3 -0
- pyvegh-0.7.0.dist-info/licenses/LICENSE +21 -0
- vegh/__init__.py +24 -0
- vegh/_core.pyd +0 -0
- vegh/analytics.py +621 -0
- vegh/cli.py +1588 -0
vegh/analytics.py
ADDED
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import List, Tuple, Dict
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.text import Text
|
|
7
|
+
from rich import box
|
|
8
|
+
from rich.layout import Layout
|
|
9
|
+
from rich.align import Align
|
|
10
|
+
|
|
11
|
+
# --- LANGUAGE DEFINITIONS ---
|
|
12
|
+
# Map extension -> (Language Name, Color)
|
|
13
|
+
# --- LANGUAGE DEFINITIONS (UPDATED) ---
|
|
14
|
+
LANG_MAP = {
|
|
15
|
+
# Systems & Low Level
|
|
16
|
+
".rs": ("Rust", "red"),
|
|
17
|
+
".c": ("C", "white"),
|
|
18
|
+
".h": ("C/C++", "white"),
|
|
19
|
+
".cpp": ("C++", "blue"),
|
|
20
|
+
".hpp": ("C++", "blue"),
|
|
21
|
+
".cc": ("C++", "blue"),
|
|
22
|
+
".cxx": ("C++", "blue"),
|
|
23
|
+
".ino": ("Arduino", "blue"), # Actually it's C++
|
|
24
|
+
".go": ("Go", "cyan"),
|
|
25
|
+
".asm": ("Assembly", "white"),
|
|
26
|
+
".s": ("Assembly", "white"),
|
|
27
|
+
".zig": ("Zig", "yellow"),
|
|
28
|
+
".f90": ("Fortran", "magenta"),
|
|
29
|
+
".f95": ("Fortran", "magenta"),
|
|
30
|
+
".f03": ("Fortran", "magenta"),
|
|
31
|
+
".f08": ("Fortran", "magenta"),
|
|
32
|
+
".f": ("Fortran", "magenta"),
|
|
33
|
+
".hs": ("Haskell", "magenta"),
|
|
34
|
+
".ml": ("OCaml", "yellow"),
|
|
35
|
+
".mli": ("OCaml", "yellow"),
|
|
36
|
+
".nim": ("Nim", "cyan"),
|
|
37
|
+
".v": ("V", "green"),
|
|
38
|
+
".ada": ("Ada", "red"),
|
|
39
|
+
".adb": ("Ada", "red"),
|
|
40
|
+
".ads": ("Ada", "red"),
|
|
41
|
+
".fs": ("F#", "blue"),
|
|
42
|
+
".fsi": ("F#", "blue"),
|
|
43
|
+
".fsx": ("F#", "blue"),
|
|
44
|
+
".sv": ("SystemVerilog", "cyan"),
|
|
45
|
+
".svh": ("SystemVerilog", "cyan"),
|
|
46
|
+
# ".v": ("Verilog", "cyan"), # Conflict with VLang
|
|
47
|
+
".pas": ("Pascal", "yellow"),
|
|
48
|
+
".pp": ("Pascal", "cyan"),
|
|
49
|
+
# Enterprise & Mobile
|
|
50
|
+
".java": ("Java", "red"),
|
|
51
|
+
".jav": ("Java", "red"),
|
|
52
|
+
".scala": ("Scala", "red"),
|
|
53
|
+
".groovy": ("Groovy", "white"),
|
|
54
|
+
".clj": ("Clojure", "green"),
|
|
55
|
+
".cljs": ("ClojureScript", "green"),
|
|
56
|
+
".cljc": ("Clojure (Common)", "green"),
|
|
57
|
+
".kt": ("Kotlin", "magenta"),
|
|
58
|
+
".kts": ("Kotlin", "magenta"),
|
|
59
|
+
".cs": ("C#", "green"),
|
|
60
|
+
".swift": ("Swift", "bright_red"),
|
|
61
|
+
".m": ("Objective-C", "blue"), # Could be Matlab too
|
|
62
|
+
".dart": ("Dart", "cyan"),
|
|
63
|
+
".ex": ("Elixir", "purple"),
|
|
64
|
+
".exs": ("Elixir", "purple"),
|
|
65
|
+
".erl": ("Erlang", "red"),
|
|
66
|
+
".gleam": ("Gleam", "pink1"),
|
|
67
|
+
".kmp": ("Kotlin Multiplatform", "magenta"),
|
|
68
|
+
# Web & Scripting
|
|
69
|
+
".py": ("Python", "blue"),
|
|
70
|
+
".pyi": ("Python", "blue"),
|
|
71
|
+
".ipynb": ("Jupyter", "yellow"),
|
|
72
|
+
".js": ("JavaScript", "yellow"),
|
|
73
|
+
".jsx": ("JavaScript (React)", "yellow"),
|
|
74
|
+
".mjs": ("JavaScript (ESM)", "yellow"),
|
|
75
|
+
".cjs": ("JavaScript (CJS)", "yellow"),
|
|
76
|
+
".coffee": ("CoffeeScript", "brown"),
|
|
77
|
+
".ts": ("TypeScript", "cyan"),
|
|
78
|
+
".tsx": ("TypeScript (React)", "cyan"),
|
|
79
|
+
".vue": ("Vue", "green"),
|
|
80
|
+
".astro": ("Astro", "orange3"),
|
|
81
|
+
".html": ("HTML", "magenta"),
|
|
82
|
+
".htm": ("HTML", "magenta"),
|
|
83
|
+
".css": ("CSS", "blue_violet"),
|
|
84
|
+
".scss": ("SCSS", "magenta"),
|
|
85
|
+
".sass": ("Sass", "magenta"),
|
|
86
|
+
".hcl": ("HCL", "purple"),
|
|
87
|
+
".tex": ("LaTeX", "blue"),
|
|
88
|
+
".less": ("LESS", "blue"),
|
|
89
|
+
".styl": ("Stylus", "green"),
|
|
90
|
+
".twig": ("Twig", "green"),
|
|
91
|
+
".svelte": ("Svelte", "orange_red1"),
|
|
92
|
+
".heex": ("Phoenix HEEx", "purple"),
|
|
93
|
+
".leex": ("Phoenix LEEx", "purple"),
|
|
94
|
+
".mjml": ("MJML (Email)", "cyan"),
|
|
95
|
+
".liquid": ("Liquid", "blue"),
|
|
96
|
+
".php": ("PHP", "magenta"),
|
|
97
|
+
".rb": ("Ruby", "red"),
|
|
98
|
+
".rake": ("Ruby", "red"),
|
|
99
|
+
".lua": ("Lua", "blue"),
|
|
100
|
+
".cr": ("Crystal", "white"),
|
|
101
|
+
".pl": ("Perl", "blue"), # Could be Prolog too
|
|
102
|
+
".pm": ("Perl", "blue"),
|
|
103
|
+
".sh": ("Shell", "green"),
|
|
104
|
+
".bash": ("Shell", "green"),
|
|
105
|
+
".zsh": ("Shell", "green"),
|
|
106
|
+
".ps1": ("PowerShell", "blue"),
|
|
107
|
+
".psm1": ("PowerShell", "blue"),
|
|
108
|
+
".bat": ("Batch", "yellow"),
|
|
109
|
+
".cmd": ("Batch", "yellow"),
|
|
110
|
+
# Game Development
|
|
111
|
+
".gd": ("GDScript", "white"),
|
|
112
|
+
".glsl": ("GLSL", "green"),
|
|
113
|
+
".hlsl": ("HLSL", "green"),
|
|
114
|
+
".wgsl": ("WGSL", "green"),
|
|
115
|
+
# Data & Config
|
|
116
|
+
".json": ("JSON", "yellow"),
|
|
117
|
+
".toml": ("TOML", "yellow"),
|
|
118
|
+
".yaml": ("YAML", "yellow"),
|
|
119
|
+
".yml": ("YAML", "yellow"),
|
|
120
|
+
".xml": ("XML", "magenta"),
|
|
121
|
+
".sql": ("SQL", "yellow"),
|
|
122
|
+
".md": ("Markdown", "white"),
|
|
123
|
+
".txt": ("Text", "white"),
|
|
124
|
+
".ini": ("INI", "white"),
|
|
125
|
+
".conf": ("Config", "white"),
|
|
126
|
+
".csv": ("CSV", "green"),
|
|
127
|
+
".tsv": ("TSV", "green"),
|
|
128
|
+
# AI & TeaserLang
|
|
129
|
+
".mojo": ("Mojo", "red"),
|
|
130
|
+
".🔥": ("Mojo", "red"),
|
|
131
|
+
".fdon": ("FDON", "bright_green"),
|
|
132
|
+
".fwon": ("FWON", "bright_green"),
|
|
133
|
+
".bxson": ("BXSON", "bright_green"),
|
|
134
|
+
# Infrastructure & Others
|
|
135
|
+
".dockerfile": ("Dockerfile", "blue"),
|
|
136
|
+
".tf": ("Terraform", "magenta"),
|
|
137
|
+
".nix": ("Nix", "cyan"),
|
|
138
|
+
".sol": ("Solidity", "bright_cyan"),
|
|
139
|
+
".r": ("R", "blue"),
|
|
140
|
+
".hack": ("Hack", "cyan"),
|
|
141
|
+
".jl": ("Julia", "purple"),
|
|
142
|
+
".wat": ("WebAssembly Text", "white"),
|
|
143
|
+
".proto": ("Protobuf", "cyan"),
|
|
144
|
+
".log": ("Log", "dim white"),
|
|
145
|
+
".prisma": ("Prisma", "white"),
|
|
146
|
+
".graphql": ("GraphQL", "magenta"),
|
|
147
|
+
".gql": ("GraphQL", "magenta"),
|
|
148
|
+
".vto": ("Vento", "bright_green"),
|
|
149
|
+
".env": ("Env Config", "red"),
|
|
150
|
+
".lock": ("Lock File", "dim white"),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# --- SLOC CONFIGURATION ---
|
|
154
|
+
SLOC_IGNORE_EXTS = {
|
|
155
|
+
".lock",
|
|
156
|
+
".md",
|
|
157
|
+
".json",
|
|
158
|
+
".svg",
|
|
159
|
+
".png",
|
|
160
|
+
".jpg",
|
|
161
|
+
".jpeg",
|
|
162
|
+
".gif",
|
|
163
|
+
".ico",
|
|
164
|
+
".pdf",
|
|
165
|
+
".zip",
|
|
166
|
+
".tar",
|
|
167
|
+
".gz",
|
|
168
|
+
".7z",
|
|
169
|
+
".rar",
|
|
170
|
+
".vegh",
|
|
171
|
+
".pyc",
|
|
172
|
+
".o",
|
|
173
|
+
".obj",
|
|
174
|
+
".dll",
|
|
175
|
+
".so",
|
|
176
|
+
".exe",
|
|
177
|
+
".class",
|
|
178
|
+
".jar",
|
|
179
|
+
".xml",
|
|
180
|
+
".yaml",
|
|
181
|
+
".yml",
|
|
182
|
+
".toml",
|
|
183
|
+
".ini",
|
|
184
|
+
".conf",
|
|
185
|
+
".cfg",
|
|
186
|
+
".txt",
|
|
187
|
+
".log",
|
|
188
|
+
".csv",
|
|
189
|
+
".tsv",
|
|
190
|
+
".sql",
|
|
191
|
+
".css",
|
|
192
|
+
".scss",
|
|
193
|
+
".sass",
|
|
194
|
+
".less",
|
|
195
|
+
".styl",
|
|
196
|
+
".html",
|
|
197
|
+
".htm",
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
COMMENT_MAP = {
|
|
201
|
+
# C-style
|
|
202
|
+
".c": "//",
|
|
203
|
+
".cpp": "//",
|
|
204
|
+
".h": "//",
|
|
205
|
+
".hpp": "//",
|
|
206
|
+
".cc": "//",
|
|
207
|
+
".cxx": "//",
|
|
208
|
+
".java": "//",
|
|
209
|
+
".cs": "//",
|
|
210
|
+
".js": "//",
|
|
211
|
+
".ts": "//",
|
|
212
|
+
".jsx": "//",
|
|
213
|
+
".tsx": "//",
|
|
214
|
+
".go": "//",
|
|
215
|
+
".rs": "//",
|
|
216
|
+
".kt": "//",
|
|
217
|
+
".swift": "//",
|
|
218
|
+
".dart": "//",
|
|
219
|
+
".scala": "//",
|
|
220
|
+
".groovy": "//",
|
|
221
|
+
".php": "//",
|
|
222
|
+
".v": "//",
|
|
223
|
+
".zig": "//",
|
|
224
|
+
".sol": "//",
|
|
225
|
+
".proto": "//",
|
|
226
|
+
".prisma": "//",
|
|
227
|
+
".glsl": "//",
|
|
228
|
+
".hlsl": "//",
|
|
229
|
+
# Script-style
|
|
230
|
+
".py": "#",
|
|
231
|
+
".rb": "#",
|
|
232
|
+
".sh": "#",
|
|
233
|
+
".bash": "#",
|
|
234
|
+
".zsh": "#",
|
|
235
|
+
".pl": "#",
|
|
236
|
+
".yaml": "#",
|
|
237
|
+
".yml": "#",
|
|
238
|
+
".toml": "#",
|
|
239
|
+
".dockerfile": "#",
|
|
240
|
+
".makefile": "#",
|
|
241
|
+
".r": "#",
|
|
242
|
+
".elixir": "#",
|
|
243
|
+
".ex": "#",
|
|
244
|
+
".exs": "#",
|
|
245
|
+
".cr": "#",
|
|
246
|
+
".jl": "#",
|
|
247
|
+
".tf": "#",
|
|
248
|
+
".nix": "#",
|
|
249
|
+
".ps1": "#",
|
|
250
|
+
# Others
|
|
251
|
+
".lua": "--",
|
|
252
|
+
".hs": "--",
|
|
253
|
+
".sql": "--",
|
|
254
|
+
".ada": "--",
|
|
255
|
+
".vhdl": "--",
|
|
256
|
+
".elm": "--",
|
|
257
|
+
".erl": "%",
|
|
258
|
+
".tex": "%",
|
|
259
|
+
".prolog": "%",
|
|
260
|
+
".vim": '"',
|
|
261
|
+
".f90": "!",
|
|
262
|
+
".f95": "!",
|
|
263
|
+
".clj": ";",
|
|
264
|
+
".cljs": ";",
|
|
265
|
+
".lisp": ";",
|
|
266
|
+
".scm": ";",
|
|
267
|
+
".asm": ";",
|
|
268
|
+
".ini": ";",
|
|
269
|
+
".bat": "REM",
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# --- FILENAME MAP ---
|
|
273
|
+
FILENAME_MAP = {
|
|
274
|
+
"dockerfile": ("Dockerfile", "blue"),
|
|
275
|
+
"docker-compose.yml": ("Docker Compose", "blue"),
|
|
276
|
+
"docker-compose.yaml": ("Docker Compose", "blue"),
|
|
277
|
+
"makefile": ("Makefile", "white"),
|
|
278
|
+
"justfile": ("Justfile", "yellow"),
|
|
279
|
+
"procfile": ("Heroku Procfile", "red"),
|
|
280
|
+
"rakefile": ("Ruby", "red"),
|
|
281
|
+
"gemfile": ("Ruby Config", "red"),
|
|
282
|
+
"cargo.toml": ("Cargo", "red"),
|
|
283
|
+
"pyproject.toml": ("Python Config", "blue"),
|
|
284
|
+
"package.json": ("NPM Config", "yellow"),
|
|
285
|
+
"tsconfig.json": ("TS Config", "cyan"),
|
|
286
|
+
"webpack.config.js": ("Webpack Config", "yellow"),
|
|
287
|
+
"tailwind.config.js": ("Tailwind Config", "cyan"),
|
|
288
|
+
"tailwind.config.ts": ("Tailwind Config", "cyan"),
|
|
289
|
+
"vite.config.js": ("Vite Config", "purple"),
|
|
290
|
+
"vite.config.ts": ("Vite Config", "purple"),
|
|
291
|
+
"postcss.config.js": ("PostCSS", "red"),
|
|
292
|
+
"go.mod": ("Go Module", "cyan"),
|
|
293
|
+
"go.sum": ("Go Sum", "cyan"),
|
|
294
|
+
".gitignore": ("Git Config", "white"),
|
|
295
|
+
".dockerignore": ("Docker Ignore", "blue"),
|
|
296
|
+
".npmignore": ("NPM Ignore", "yellow"),
|
|
297
|
+
".veghignore": ("Vegh Ignore", "bright_green"),
|
|
298
|
+
".editorconfig": ("Editor Config", "white"),
|
|
299
|
+
".env.example": ("Env Template", "dim white"),
|
|
300
|
+
".env.production": ("Env Production", "red"),
|
|
301
|
+
".env.local": ("Env Development", "green"),
|
|
302
|
+
"build.gradle": ("Gradle", "green"),
|
|
303
|
+
"build.gradle.kts": ("Gradle Kotlin", "green"),
|
|
304
|
+
"settings.gradle": ("Gradle Settings", "green"),
|
|
305
|
+
"settings.gradle.kts": ("Gradle Settings Kotlin", "green"),
|
|
306
|
+
"pom.xml": ("Maven", "red"),
|
|
307
|
+
"pubspec.yaml": ("Flutter Config", "blue"),
|
|
308
|
+
"vagrantfile": ("Vagrant", "blue"),
|
|
309
|
+
"jenkinsfile": ("Groovy", "white"),
|
|
310
|
+
"wrangler.toml": ("Cloudflare", "orange3"),
|
|
311
|
+
"vercel.json": ("Vercel", "white"),
|
|
312
|
+
"netlify.toml": ("Netlify", "cyan"),
|
|
313
|
+
"next.config.js": ("Next.js Config", "white"),
|
|
314
|
+
"nuxt.config.js": ("Nuxt.js Config", "green"),
|
|
315
|
+
"gatsby-config.js": ("Gatsby Config", "purple"),
|
|
316
|
+
"package-lock.json": ("NPM Lock", "yellow"),
|
|
317
|
+
"pnpm-lock.yaml": ("PNPM Lock", "yellow"),
|
|
318
|
+
"pnpm-workspace.yaml": ("PNPM Workspace", "yellow"),
|
|
319
|
+
"firebase.json": ("Firebase Config", "yellow"),
|
|
320
|
+
"deno.json": ("Deno Config", "cyan"),
|
|
321
|
+
"deno.jsonc": ("Deno Config", "cyan"),
|
|
322
|
+
".prettierrc": ("Prettier Config", "white"),
|
|
323
|
+
".eslintrc": ("ESLint Config", "white"),
|
|
324
|
+
".eslintrc.json": ("ESLint Config", "white"),
|
|
325
|
+
".eslintrc.js": ("ESLint Config", "white"),
|
|
326
|
+
"pyrightconfig.json": ("Pyright Config", "blue"),
|
|
327
|
+
"tslint.json": ("TSLint Config", "cyan"),
|
|
328
|
+
"composer.json": ("Composer (PHP)", "magenta"),
|
|
329
|
+
"composer.lock": ("Composer Lock", "magenta"),
|
|
330
|
+
"setup.py": ("Python Setup", "blue"),
|
|
331
|
+
"requirements.txt": ("Python Requirements", "blue"),
|
|
332
|
+
"mix.exs": ("Elixir Mix", "purple"),
|
|
333
|
+
"rebar.config": ("Erlang Rebar", "red"),
|
|
334
|
+
"import_map.json": ("Deno Import Map", "cyan"),
|
|
335
|
+
".babelrc": ("Babel Config", "yellow"),
|
|
336
|
+
"babel.config.js": ("Babel Config", "yellow"),
|
|
337
|
+
".nycrc": ("Istanbul Config", "yellow"),
|
|
338
|
+
".swcrc": ("SWC Config", "cyan"),
|
|
339
|
+
# CI/CD & DevOps
|
|
340
|
+
".gitlab-ci.yml": ("GitLab CI", "orange_red1"),
|
|
341
|
+
"cloudformation.yaml": ("CloudFormation", "orange3"),
|
|
342
|
+
"cloudformation.yml": ("CloudFormation", "orange3"),
|
|
343
|
+
"fly.toml": ("Fly.io Config", "purple"),
|
|
344
|
+
# CodeTease Specific
|
|
345
|
+
".veghhooks.json": ("Vegh Hooks", "bright_green"),
|
|
346
|
+
"sensify.yaml": ("Sensify Config", "bright_green"),
|
|
347
|
+
"carade.conf": ("Carade Config", "bright_green"),
|
|
348
|
+
# Special Cases
|
|
349
|
+
"license": ("License", "white"),
|
|
350
|
+
"readme": ("Readme", "white"),
|
|
351
|
+
"license.md": ("License", "white"),
|
|
352
|
+
"readme.md": ("Readme", "white"),
|
|
353
|
+
"license.txt": ("License", "white"),
|
|
354
|
+
"readme.txt": ("Readme", "white"),
|
|
355
|
+
"contributing.md": ("Contributing", "white"),
|
|
356
|
+
"contributing.txt": ("Contributing", "white"),
|
|
357
|
+
"changelog.md": ("Changelog", "white"),
|
|
358
|
+
"changelog.txt": ("Changelog", "white"),
|
|
359
|
+
"security.md": ("Security", "white"),
|
|
360
|
+
"security.txt": ("Security", "white"),
|
|
361
|
+
"code_of_conduct.md": ("Code of Conduct", "white"),
|
|
362
|
+
"code_of_conduct.txt": ("Code of Conduct", "white"),
|
|
363
|
+
"agents.md": (
|
|
364
|
+
"Agents",
|
|
365
|
+
"bright_green",
|
|
366
|
+
), # For AI coding agents, rare but possible. easily find in big repositories
|
|
367
|
+
"authors.md": ("Authors", "white"),
|
|
368
|
+
"authors": ("Authors", "white"),
|
|
369
|
+
"version.txt": ("Version", "white"),
|
|
370
|
+
"version.md": ("Version", "white"),
|
|
371
|
+
"version": ("Version", "white"),
|
|
372
|
+
"codeowners": ("Code Owners", "white"),
|
|
373
|
+
"funding.yml": ("Funding", "white"),
|
|
374
|
+
"todo.md": ("Todo", "white"),
|
|
375
|
+
"todo": ("Todo", "white"),
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class ProjectStats:
|
|
380
|
+
def __init__(self):
|
|
381
|
+
self.total_files = 0
|
|
382
|
+
self.total_loc = 0
|
|
383
|
+
self.lang_stats: Dict[str, Dict] = {}
|
|
384
|
+
|
|
385
|
+
def add_file(self, path_str: str, loc: int):
|
|
386
|
+
self.total_files += 1
|
|
387
|
+
self.total_loc += loc
|
|
388
|
+
|
|
389
|
+
path = Path(path_str)
|
|
390
|
+
# .lower() handles both .s and .S
|
|
391
|
+
ext = path.suffix.lower()
|
|
392
|
+
name = path.name.lower()
|
|
393
|
+
|
|
394
|
+
# Identify Language
|
|
395
|
+
lang, color = "Other", "white"
|
|
396
|
+
|
|
397
|
+
if name in FILENAME_MAP:
|
|
398
|
+
lang, color = FILENAME_MAP[name]
|
|
399
|
+
elif ext in LANG_MAP:
|
|
400
|
+
lang, color = LANG_MAP[ext]
|
|
401
|
+
|
|
402
|
+
# Update Stats
|
|
403
|
+
if lang not in self.lang_stats:
|
|
404
|
+
self.lang_stats[lang] = {"files": 0, "loc": 0, "color": color}
|
|
405
|
+
|
|
406
|
+
self.lang_stats[lang]["files"] += 1
|
|
407
|
+
self.lang_stats[lang]["loc"] += loc
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _make_bar(label: str, percent: float, color: str, width: int = 30) -> Text:
|
|
411
|
+
"""Manually renders a progress bar using unicode blocks."""
|
|
412
|
+
filled_len = int((percent / 100.0) * width)
|
|
413
|
+
unfilled_len = width - filled_len
|
|
414
|
+
|
|
415
|
+
bar_str = ("█" * filled_len) + ("░" * unfilled_len)
|
|
416
|
+
|
|
417
|
+
text = Text()
|
|
418
|
+
text.append(f"{label:<20}", style=f"bold {color}")
|
|
419
|
+
text.append(f"{bar_str} ", style=color)
|
|
420
|
+
text.append(f"{percent:>5.1f}%", style="bold white")
|
|
421
|
+
return text
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def calculate_sloc(file_path: str) -> int:
|
|
425
|
+
"""Calculates Source Lines of Code (SLOC).
|
|
426
|
+
Excludes empty lines and full-line comments.
|
|
427
|
+
"""
|
|
428
|
+
path = Path(file_path)
|
|
429
|
+
ext = path.suffix.lower()
|
|
430
|
+
|
|
431
|
+
if ext in SLOC_IGNORE_EXTS:
|
|
432
|
+
return 0
|
|
433
|
+
|
|
434
|
+
comment_prefix = COMMENT_MAP.get(ext)
|
|
435
|
+
|
|
436
|
+
count = 0
|
|
437
|
+
try:
|
|
438
|
+
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
439
|
+
for line in f:
|
|
440
|
+
line = line.strip()
|
|
441
|
+
if not line:
|
|
442
|
+
continue
|
|
443
|
+
if comment_prefix and line.startswith(comment_prefix):
|
|
444
|
+
continue
|
|
445
|
+
count += 1
|
|
446
|
+
except Exception:
|
|
447
|
+
pass # Handle binary or read errors gracefully
|
|
448
|
+
|
|
449
|
+
return count
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def scan_sloc(path: str) -> List[Tuple[str, int]]:
|
|
453
|
+
"""Scans a directory for SLOC, using core dry_run_snap for traversal."""
|
|
454
|
+
# We need to import dry_run_snap here or pass it in.
|
|
455
|
+
# To avoid circular imports, we'll try to import it inside the function
|
|
456
|
+
from ._core import dry_run_snap
|
|
457
|
+
|
|
458
|
+
results = []
|
|
459
|
+
|
|
460
|
+
# Use dry_run_snap to get the file list (respecting .gitignore/veghignore)
|
|
461
|
+
# dry_run_snap returns (path, size). We just want the path.
|
|
462
|
+
files = dry_run_snap(path)
|
|
463
|
+
|
|
464
|
+
base_path = Path(path)
|
|
465
|
+
|
|
466
|
+
for relative_path, _ in files:
|
|
467
|
+
full_path = base_path / relative_path
|
|
468
|
+
sloc = calculate_sloc(str(full_path))
|
|
469
|
+
results.append((relative_path, sloc))
|
|
470
|
+
|
|
471
|
+
return results
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def render_dashboard(
|
|
475
|
+
console: Console,
|
|
476
|
+
file_name: str,
|
|
477
|
+
raw_results: List[Tuple[str, int]],
|
|
478
|
+
metric_name: str = "LOC",
|
|
479
|
+
):
|
|
480
|
+
"""Draws the beautiful CodeTease Analytics Dashboard."""
|
|
481
|
+
|
|
482
|
+
# 1. Process Data
|
|
483
|
+
stats = ProjectStats()
|
|
484
|
+
for path, loc in raw_results:
|
|
485
|
+
if loc > 0:
|
|
486
|
+
stats.add_file(path, loc)
|
|
487
|
+
|
|
488
|
+
if stats.total_loc == 0:
|
|
489
|
+
console.print(
|
|
490
|
+
"[yellow]No code detected (or binary only). Is this a ghost project?[/yellow]"
|
|
491
|
+
)
|
|
492
|
+
return
|
|
493
|
+
|
|
494
|
+
sorted_langs = sorted(
|
|
495
|
+
stats.lang_stats.items(), key=lambda item: item[1]["loc"], reverse=True
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
# 2. Build Layout
|
|
499
|
+
layout = Layout()
|
|
500
|
+
layout.split(
|
|
501
|
+
Layout(name="header", size=3),
|
|
502
|
+
Layout(name="body", ratio=1),
|
|
503
|
+
Layout(name="footer", size=3),
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
layout["body"].split_row(
|
|
507
|
+
Layout(name="left", ratio=1), Layout(name="right", ratio=1)
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# --- Header ---
|
|
511
|
+
title_text = Text(
|
|
512
|
+
f"📊 Vegh Analytics ({metric_name}): {file_name}",
|
|
513
|
+
style="bold white on blue",
|
|
514
|
+
justify="center",
|
|
515
|
+
)
|
|
516
|
+
layout["header"].update(Panel(title_text, box=box.HEAVY))
|
|
517
|
+
|
|
518
|
+
# --- Left: Detailed Table ---
|
|
519
|
+
table = Table(box=box.SIMPLE_HEAD, expand=True)
|
|
520
|
+
table.add_column("Lang", style="bold")
|
|
521
|
+
table.add_column("Files", justify="right")
|
|
522
|
+
table.add_column(metric_name, justify="right", style="green")
|
|
523
|
+
table.add_column("%", justify="right")
|
|
524
|
+
|
|
525
|
+
for lang, data in sorted_langs:
|
|
526
|
+
percent = (data["loc"] / stats.total_loc) * 100
|
|
527
|
+
table.add_row(
|
|
528
|
+
f"[{data['color']}]{lang}[/{data['color']}]",
|
|
529
|
+
str(data["files"]),
|
|
530
|
+
f"{data['loc']:,}",
|
|
531
|
+
f"{percent:.1f}%",
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
layout["left"].update(
|
|
535
|
+
Panel(table, title="[bold]Breakdown[/bold]", border_style="cyan")
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
# --- Right: Custom Manual Bar Chart ---
|
|
539
|
+
chart_content = Text()
|
|
540
|
+
|
|
541
|
+
# Take Top 12 languages
|
|
542
|
+
for i, (lang, data) in enumerate(sorted_langs[:12]):
|
|
543
|
+
percent = (data["loc"] / stats.total_loc) * 100
|
|
544
|
+
bar = _make_bar(lang, percent, data["color"])
|
|
545
|
+
chart_content.append(bar)
|
|
546
|
+
chart_content.append("\n")
|
|
547
|
+
|
|
548
|
+
if len(sorted_langs) > 12:
|
|
549
|
+
chart_content.append(
|
|
550
|
+
f"\n... and {len(sorted_langs) - 12} others", style="dim italic"
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
layout["right"].update(
|
|
554
|
+
Panel(
|
|
555
|
+
Align.center(chart_content, vertical="middle"),
|
|
556
|
+
title="[bold]Distribution[/bold]",
|
|
557
|
+
border_style="green",
|
|
558
|
+
)
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
# --- Footer: Summary & Fun Comment ---
|
|
562
|
+
if sorted_langs:
|
|
563
|
+
top_lang = sorted_langs[0][0]
|
|
564
|
+
else:
|
|
565
|
+
top_lang = "Other"
|
|
566
|
+
|
|
567
|
+
comment = "Code Hard, Play Hard! 🚀"
|
|
568
|
+
|
|
569
|
+
# Logic Fun Comment
|
|
570
|
+
if top_lang == "Rust":
|
|
571
|
+
comment = "Blazingly Fast! 🦀"
|
|
572
|
+
elif top_lang == "Python":
|
|
573
|
+
comment = "Snake Charmer! 🐍"
|
|
574
|
+
elif top_lang == "Haskell":
|
|
575
|
+
comment = "Purely Functional... and confusing! 😵💫"
|
|
576
|
+
elif top_lang == "Mojo":
|
|
577
|
+
comment = "AI Speedster! 🔥"
|
|
578
|
+
elif top_lang == "Solidity":
|
|
579
|
+
comment = "Wen Lambo? 🏎️"
|
|
580
|
+
elif top_lang == "Elixir":
|
|
581
|
+
comment = "Scalability God! 💜"
|
|
582
|
+
elif top_lang == "Astro":
|
|
583
|
+
comment = "To the stars! 🚀"
|
|
584
|
+
elif top_lang == "CSS":
|
|
585
|
+
comment = "Center a div? Good luck! 🎨"
|
|
586
|
+
elif "React" in top_lang:
|
|
587
|
+
comment = "Component Heaven! ⚛️"
|
|
588
|
+
elif top_lang in ["JavaScript", "TypeScript", "Vue", "Svelte"]:
|
|
589
|
+
comment = "Web Scale! 🌐"
|
|
590
|
+
elif top_lang in ["Assembly", "C", "C++"]:
|
|
591
|
+
comment = "Low Level Wizardry! 🧙♂️"
|
|
592
|
+
elif top_lang in ["FDON", "FWON", "BXSON"]:
|
|
593
|
+
comment = "Teasers! ⚡"
|
|
594
|
+
elif top_lang == "HTML":
|
|
595
|
+
comment = "How To Meet Ladies? 😉"
|
|
596
|
+
elif top_lang == "Go":
|
|
597
|
+
comment = "Gopher it! 🐹"
|
|
598
|
+
elif top_lang == "Java":
|
|
599
|
+
comment = "Enterprise Grade! ☕"
|
|
600
|
+
elif top_lang == "C#":
|
|
601
|
+
comment = "Microsoft Magic! 🪟"
|
|
602
|
+
elif top_lang == "PHP":
|
|
603
|
+
comment = "Elephant in the room! 🐘"
|
|
604
|
+
elif top_lang == "Swift":
|
|
605
|
+
comment = "Feeling Swift? 🍏"
|
|
606
|
+
elif top_lang == "Dart":
|
|
607
|
+
comment = "Fluttering away! 🐦"
|
|
608
|
+
elif top_lang == "SQL":
|
|
609
|
+
comment = "DROP TABLE production; 💀"
|
|
610
|
+
elif top_lang == "Terraform":
|
|
611
|
+
comment = "Infrastructure as Code! 🏗️"
|
|
612
|
+
elif top_lang == "Dockerfile":
|
|
613
|
+
comment = "Containerized! 🐳"
|
|
614
|
+
|
|
615
|
+
summary = f"[bold]Total {metric_name}:[/bold] [green]{stats.total_loc:,}[/green] | [bold]Analyzed Files:[/bold] {stats.total_files} | [italic]{comment}[/italic]"
|
|
616
|
+
|
|
617
|
+
layout["footer"].update(
|
|
618
|
+
Panel(Text.from_markup(summary, justify="center"), border_style="blue")
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
console.print(layout)
|