| #!/usr/bin/env python3 |
| |
| from pathlib import Path |
| |
| |
| try: |
| # VS Code settings allow comments and trailing commas, which are not valid JSON. |
| import json5 as json # type: ignore[import] |
| |
| HAS_JSON5 = True |
| except ImportError: |
| import json # type: ignore[no-redef] |
| |
| HAS_JSON5 = False |
| |
| |
| ROOT_FOLDER = Path(__file__).absolute().parent.parent |
| VSCODE_FOLDER = ROOT_FOLDER / ".vscode" |
| RECOMMENDED_SETTINGS = VSCODE_FOLDER / "settings_recommended.json" |
| SETTINGS = VSCODE_FOLDER / "settings.json" |
| |
| |
| # settings can be nested, so we need to recursively update the settings. |
| def deep_update(d: dict, u: dict) -> dict: # type: ignore[type-arg] |
| for k, v in u.items(): |
| if isinstance(v, dict): |
| d[k] = deep_update(d.get(k, {}), v) |
| elif isinstance(v, list): |
| d[k] = d.get(k, []) + v |
| else: |
| d[k] = v |
| return d |
| |
| |
| def main() -> None: |
| recommended_settings = json.loads(RECOMMENDED_SETTINGS.read_text()) |
| try: |
| current_settings_text = SETTINGS.read_text() |
| except FileNotFoundError: |
| current_settings_text = "{}" |
| |
| try: |
| current_settings = json.loads(current_settings_text) |
| except ValueError as ex: # json.JSONDecodeError is a subclass of ValueError |
| if HAS_JSON5: |
| raise SystemExit("Failed to parse .vscode/settings.json.") from ex |
| raise SystemExit( |
| "Failed to parse .vscode/settings.json. " |
| "Maybe it contains comments or trailing commas. " |
| "Try `pip install json5` to install an extended JSON parser." |
| ) from ex |
| |
| settings = deep_update(current_settings, recommended_settings) |
| |
| SETTINGS.write_text( |
| json.dumps( |
| settings, |
| indent=4, |
| ) |
| + "\n", # add a trailing newline |
| encoding="utf-8", |
| ) |
| |
| |
| if __name__ == "__main__": |
| main() |