Script to autoformat all files

This commit is contained in:
Kovid Goyal 2026-08-06 14:33:30 +05:30
parent 21772e43cd
commit 39feb5d3eb
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 155 additions and 26 deletions

121
autoformat Executable file
View file

@ -0,0 +1,121 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2026, Kovid Goyal <kovid at kovidgoyal.net>
import concurrent.futures
import hashlib
import json
import os
import subprocess
import sys
import tempfile
import threading
base = os.path.dirname(os.path.abspath(__file__))
ruff = subprocess.Popen(['ruff', 'format'], cwd=base, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
go = subprocess.Popen('gofmt -s -l -w tools kittens'.split(), cwd=base, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
ruff_output = b''
go_output = b''
def wait_ruff() -> None:
global ruff_output
ruff_output = ruff.communicate()[0]
def wait_go() -> None:
global go_output
go_output = go.communicate()[0]
threading.Thread(target=wait_ruff).start()
threading.Thread(target=wait_go).start()
clang_files = []
for x in os.listdir(base):
if x in ('dist', 'build', 'bypy', '3rdparty') or x.startswith('.'):
continue
for root, dirnames, files in os.walk(os.path.join(base, x)):
for file in files:
if file.startswith('wayland-') and os.path.basename(root) == 'glfw':
continue
ext = os.path.splitext(file)[1]
if ext in ('.c', '.h', '.m'):
clang_files.append(os.path.join(root, file))
CACHE_DIR = os.path.join(base, '.cache', 'autoformat')
CACHE_FILE = os.path.join(CACHE_DIR, 'clang_format.json')
def file_hash(path: str) -> str:
h = hashlib.md5()
with open(path, 'rb') as f:
h.update(f.read())
return h.hexdigest()
def load_cache() -> dict[str, str]:
try:
with open(CACHE_FILE) as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return {}
def save_cache(cache: dict[str, str]) -> None:
os.makedirs(CACHE_DIR, exist_ok=True)
fd, tmp = tempfile.mkstemp(dir=CACHE_DIR)
try:
with os.fdopen(fd, 'w') as f:
json.dump(cache, f, indent=2)
os.replace(tmp, CACHE_FILE)
except Exception:
os.unlink(tmp)
raise
cache: dict[str, str] = load_cache()
cache_lock = threading.Lock()
def run_clang_format(file_path: str) -> tuple[bool, str, str]:
rel_path = os.path.relpath(file_path, base)
current_hash = file_hash(file_path)
with cache_lock:
if cache.get(rel_path) == current_hash:
return True, '', ''
cmd = ['clang-format', '-style=file', '-i', file_path]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
if result.returncode != 0:
return False, file_path, result.stderr
new_hash = file_hash(file_path)
with cache_lock:
cache[rel_path] = new_hash
return True, '', ''
clang_failed = False
with concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
futures = {executor.submit(run_clang_format, f): f for f in clang_files}
for future in concurrent.futures.wait(futures)[0]:
success, file_path, error_msg = future.result()
if not success:
print(f'[FAILED] {file_path}\n{error_msg}', file=sys.stderr)
clang_failed = True
save_cache(cache)
ruff.wait()
go.wait()
if ruff.wait() != 0:
sys.stderr.buffer.write(ruff_output)
raise SystemExit('Formatting of Python code failed')
if go.wait() != 0:
sys.stderr.buffer.write(go_output)
raise SystemExit('Formatting of Go code failed')
raise SystemExit('Formatting of C files failed' if clang_failed else 0)

View file

@ -1097,15 +1097,17 @@ def is_valid_slot(x: str) -> TypeGuard[Slot]:
VALID_VAR_TYPES: frozenset[str] = frozenset({'uint', 'int', 'float', 'double', 'bool'})
SHADER_ANIMATION_EVENTS: frozenset[str] = frozenset({
'pointer-left-button-press',
'os-window-focus-in',
'os-window-focus-out',
'window-focus-in',
'window-focus-out',
'tab-change',
'bell-in-window',
})
SHADER_ANIMATION_EVENTS: frozenset[str] = frozenset(
{
'pointer-left-button-press',
'os-window-focus-in',
'os-window-focus-out',
'window-focus-in',
'window-focus-out',
'tab-change',
'bell-in-window',
}
)
def is_valid_animation_event(name: str) -> bool:
@ -1123,12 +1125,12 @@ def parse_animation_events(raw: str) -> tuple[str, ...]:
def parse_css_animation_curve(spec: str) -> EasingFunction:
_NAMED: dict[str, tuple[str, str]] = {
'ease-in-out': ('cubic-bezier', '0.42, 0, 0.58, 1'),
'linear': ('cubic-bezier', '0, 0, 1, 1'),
'ease': ('cubic-bezier', '0.25, 0.1, 0.25, 1'),
'ease-out': ('cubic-bezier', '0, 0, 0.58, 1'),
'ease-in': ('cubic-bezier', '0.42, 0, 1, 1'),
'step-start': ('steps', '1, start'),
'step-end': ('steps', '1, end'),
'linear': ('cubic-bezier', '0, 0, 1, 1'),
'ease': ('cubic-bezier', '0.25, 0.1, 0.25, 1'),
'ease-out': ('cubic-bezier', '0, 0, 0.58, 1'),
'ease-in': ('cubic-bezier', '0.42, 0, 1, 1'),
'step-start': ('steps', '1, start'),
'step-end': ('steps', '1, end'),
}
def make(func_name: str, params: str) -> EasingFunction:
@ -1191,11 +1193,11 @@ class Group(TypedDict):
output_texture: NamedTexture
shaders: tuple[str, ...]
vars: dict[str, tuple[str, str]]
animation_start: tuple[str, ...] # empty = no animation
animation_curve: EasingFunction # parsed easing curve
animation_step: int # nanoseconds between animation samples
animation_end_events: tuple[str, ...] # events that stop the animation
animation_end_duration: int | None # nanoseconds; None = no time limit
animation_start: tuple[str, ...] # empty = no animation
animation_curve: EasingFunction # parsed easing curve
animation_step: int # nanoseconds between animation samples
animation_end_events: tuple[str, ...] # events that stop the animation
animation_end_duration: int | None # nanoseconds; None = no time limit
class Pipeline(TypedDict):
@ -1224,10 +1226,16 @@ def parse_pipeline_definition(lines: Iterable[str], pipeline_name: str, pipeline
def init_group(*shaders: str) -> Group:
return {
'viewport_pos': (0, 0), 'viewport_size': (1, 1), 'output_texture': NamedTexture.default,
'shaders': shaders, 'vars': {},
'animation_start': (), 'animation_curve': EasingFunction(),
'animation_step': ANIMATION_SAMPLE_WAIT, 'animation_end_events': (), 'animation_end_duration': None,
'viewport_pos': (0, 0),
'viewport_size': (1, 1),
'output_texture': NamedTexture.default,
'shaders': shaders,
'vars': {},
'animation_start': (),
'animation_curve': EasingFunction(),
'animation_step': ANIMATION_SAMPLE_WAIT,
'animation_end_events': (),
'animation_end_duration': None,
}
for line in lines:

View file

@ -3,6 +3,7 @@ copy_resource: fonts
copy_resource: bypy/b/linux/64/pkg/slang
add_to_path: bypy/b/linux/64/pkg/slang/bin
prepend_to_path: kitty/launcher
pre_commit: ./autoformat
# System Instructions & Project Context
@ -29,7 +30,6 @@ make debug
Execute the following two commands to fix any formatting issues in your code:
```
ruff check --fix
git ls-files '*.go' | xargs gofmt -w -s -l
```
Run the following command to type check python files:
@ -80,7 +80,7 @@ using:
## Verification Pipeline
Before declaring a task complete, you must follow this exact verification lifecycle:
1. Run the linting tools above to cleanup any formatting issues in your code
1. Run the linting tools above to cleanup any simple issues in your code
2. Run the local **Build Command** to guarantee zero compilation or compilation-stage type errors.
3. Run the local **Test Command** to run the full test suite
4. If errors occur, analyze the stdout logs completely before writing a fix. Do not guess.