diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f6b8fdf --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: LLVM diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..adeabc7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,29 @@ +# EditorConfig is awesome: https://EditorConfig.org +# Ensures consistent coding styles for multiple developers working on the same project across various editors and IDEs. + +root = true + +# All files +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +# Python files - 4 space indent +[*.py] +indent_size = 4 + +# Markdown files - preserve whitespace for formatting +[*.md] +trim_trailing_whitespace = false + +# Makefile - requires tabs +[Makefile] +indent_style = tab + +# Make files - requires tabs +[*.make] +indent_style = tab diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ad65d50 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +# Ignore build artifacts and generated files +build/ +managed_components/ +.direnv/ +*.lock + +# Ignore sdkconfig (generated) +sdkconfig +sdkconfig.old + +# SVGs are formatted with svgo instead +*.svg +# Ignore dependencies +dependencies.lock diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..a68aa02 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,12 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "avoid", + "endOfLine": "lf", + "proseWrap": "preserve" +} diff --git a/flake.nix b/flake.nix index a9c1a83..b4e20cd 100644 --- a/flake.nix +++ b/flake.nix @@ -24,6 +24,12 @@ esp-idf pkgs.python3 pkgs.python3Packages.invoke + # Formatting tools + pkgs.clang-tools + pkgs.nodePackages.prettier + # pkgs.nodePackages.svgo + pkgs.black + pkgs.nixfmt ]; }; }; diff --git a/tasks.py b/tasks.py index 8e745c4..a6096f2 100644 --- a/tasks.py +++ b/tasks.py @@ -1,6 +1,8 @@ from invoke import task import os import shutil +import sys + @task def cleanbuild(c): @@ -41,7 +43,7 @@ def clean(c): c.run("idf.py fullclean") -@task +@task def config(c): """Open menuconfig to edit project settings""" c.run("idf.py menuconfig --color-scheme=monochrome", pty=True) @@ -52,11 +54,13 @@ def saveconfig(c): """Save current config as sdkconfig.defaults""" c.run("idf.py save-defconfig") + @task def update(c): """Update project dependencies""" c.run("idf.py update-dependencies") + @task def reset(c): """Reset project to clean state: remove build, config, and managed components""" @@ -68,4 +72,99 @@ def reset(c): shutil.rmtree("build") if os.path.exists("managed_components"): shutil.rmtree("managed_components") - + + +@task +def format(c): + """Format all source files with clang-format, black, prettier, nixfmt, and svgo""" + missing_tools = [] + + print("Formatting C files...") + result = c.run( + "find main components -name '*.c' -o -name '*.h' | xargs clang-format -i", + warn=True, + ) + if result and not result.ok: + missing_tools.append("clang-format") + + print("Formatting Python files...") + result = c.run("black tasks.py", warn=True) + if result and not result.ok: + missing_tools.append("black") + + print("Formatting Nix files...") + result = c.run("nixfmt flake.nix", warn=True) + if result and not result.ok: + missing_tools.append("nixfmt") + + print("Formatting SVG files...") + result = c.run( + "find . -name '*.svg' -not -path './build/*' -not -path './managed_components/*' | xargs svgo", + warn=True, + ) + if result and not result.ok: + missing_tools.append("svgo") + + print("Formatting other files...") + result = c.run("prettier --write '**/*.{js,json,yaml,yml,md,html,css}'", warn=True) + if result and not result.ok: + missing_tools.append("prettier") + + if missing_tools: + print(f"\n❌ ERROR: Missing formatting tools: {', '.join(missing_tools)}") + print("Please install them or reload the nix-shell.") + sys.exit(1) + + +@task +def format_check(c): + """Check if all files are formatted correctly""" + missing_tools = [] + format_errors = [] + + print("Checking C file formatting...") + result = c.run( + "find main components -name '*.c' -o -name '*.h' | xargs clang-format --dry-run --Werror", + warn=True, + ) + if result: + if result.return_code == 127: # Command not found + missing_tools.append("clang-format") + elif not result.ok: + format_errors.append("C files") + + print("Checking Python file formatting...") + result = c.run("black --check tasks.py", warn=True) + if result: + if result.return_code == 127: + missing_tools.append("black") + elif not result.ok: + format_errors.append("Python files") + + print("Checking Nix file formatting...") + result = c.run("nixfmt --check flake.nix", warn=True) + if result: + if result.return_code == 127: + missing_tools.append("nixfmt") + elif not result.ok: + format_errors.append("Nix files") + + print("Checking other file formatting...") + result = c.run("prettier --check '**/*.{js,json,yaml,yml,md,html,css}'", warn=True) + if result: + if result.return_code == 127: + missing_tools.append("prettier") + elif not result.ok: + format_errors.append("JS/JSON/YAML/HTML/CSS files") + + if missing_tools: + print(f"\n❌ ERROR: Missing formatting tools: {', '.join(missing_tools)}") + print("Please install them or reload the nix-shell.") + sys.exit(1) + + if format_errors: + print(f"\n❌ ERROR: Formatting issues in: {', '.join(format_errors)}") + print("Run 'invoke format' to fix them.") + sys.exit(1) + + print("\n✅ All files are correctly formatted!")