Skip to content

Commit

Permalink
Add source
Browse files Browse the repository at this point in the history
  • Loading branch information
kraifpatrik committed Oct 12, 2024
1 parent 5f9f169 commit 2cd2d2e
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
format-gml.zip
29 changes: 29 additions & 0 deletions .jsbeautifyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"indent_size": 4,
"indent_char": " ",
"indent_with_tabs": true,
"editorconfig": false,
"eol": "\n",
"end_with_newline": true,
"indent_level": 0,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"space_in_paren": false,
"space_in_empty_paren": false,
"jslint_happy": false,
"space_after_anon_function": true,
"space_after_named_function": false,
"brace_style": "expand,preserve-inline",
"unindent_chained_methods": false,
"break_chained_methods": false,
"keep_array_indentation": false,
"unescape_strings": false,
"wrap_line_length": 120,
"e4x": true,
"comma_first": false,
"operator_position": "after-newline",
"indent_empty_lines": false,
"templating": [
"auto"
]
}
94 changes: 93 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,94 @@
# format-gml
Tiny tool and a Git hook for automatic formatting of GML code

> Tiny tool and a Git hook for automatic formatting of GML code
[![License](https://img.shields.io/github/license/blueburncz/format-gml)](LICENSE)
[![Discord](https://img.shields.io/discord/298884075585011713?label=Discord)](https://discord.gg/ep2BGPm)

## Table of Contents

* [About](#about)
* [How to set up](#how-to-set-up)
* [As a repo owner](#as-a-repo-owner)
* [As a contributor](#as-a-contributor)
* [Common issues](#common-issues)

## About

format-gml is a simple Python script that uses [js-beautify](https://github.com/beautifier/js-beautify) to format GML files, designed primarily to ensure that all contributors to an open-source GameMaker project use the same code formatting style. This is achieved with a pre-commit Git hook, which checks whether all staged GML files follow the style defined in a file `.jsbeautifyrc` placed in the root of the repo. If a staged GML file doesn't follow the formatting style, it's not allowed to be committed before it's fixed. This can be done simply by running the tool.

## How to set up

### As a repo owner
First, you need to download a release of format-gml and extract it into the root of your repo. Don't forget to commit all the extracted files! 🙂

Next, install [Python 3](https://www.python.org/downloads/) and the required packages by running the following command:

```sh
pip3 install -r requirements.txt
```

You may want to customize the `.jsbeautifyrc` file to match your preferred code formatting style. Our default setup follows the [Allman style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style), with tabs for indentation (size 4) and a maximum line length of 120 characters. You can have a look here for all available options: <https://github.com/beautifier/js-beautify?tab=readme-ov-file#options>.

To format all GML files present in your repo with the configure style, run the following command and commit the changes.

```sh
python3 format-gml.py --all
```

Afterwards, set up the hook by running:

```gml
git config core.hooksPath hooks
```

And that's it! From now on, when you try to commit changes to GML files within the repo, the hook won't allow you to do so if they're not properly formatted. To fix their formatting, simply run `format-gml.py` with out any arguments like so:

```sh
python3 format-gml.py
```

### As a contributor

1. Install [Python 3](https://www.python.org/downloads/) and the required packages by running the following command from the root of the repo:

```sh
pip3 install -r requirements.txt
```

2. Set up the hook by running:

```gml
git config core.hooksPath hooks
```

3. When you're not allowed to commit a file because of its formatting, run the following command and stage the changes:

```sh
python3 format-gml.py
```

## Common issues

Since js-beautify is a JavaScript formatter, it doesn't work properly on GameMaker in all cases.

1. `$"these strings"`

Handled automatically inside of `format-gml.py` by removing all whitespace between character `$` and `"`.

2. `#macro`s

Currently the only fix for those is to surround them with `/* beautify ignore:start */` and `/* beautify ignore:end */` like so:

```gml
/* beautify ignore:start */
#macro MY_FANCY_MACRO \
do
{ \
some_stuff_here(); \
} \
until (1)
/* beautify ignore:end */
```
If you find more, please let us know via an issue or contact us on our Discord server (link at the top).
125 changes: 125 additions & 0 deletions format-gml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import jsbeautifier
import json
import os
import re
import subprocess
import sys

VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_PATCH = 0
VERSION_STRING = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}"

HELP_MESSAGE = """
Usage: format-gml [-h, -v, --validate, --staged, --all, --file FILE]
Arguments:
-h - Show this help message and exit.
-v - Show version and exit.
--validate - Check whether all staged GML files are properly formatted and exit with status 0 on success or 1 on fail.
--staged - Format all staged GML files. This is the default option.
--all - Format all GML files in the repo.
--file - Format only given file.
"""[
1:
]

OPTIONS_PATH = "./.jsbeautifyrc"

if os.path.exists(OPTIONS_PATH):
with open(OPTIONS_PATH, "r") as f:
OPTIONS = json.load(f)
else:
OPTIONS = None


def beautify_file(filepath):
res = jsbeautifier.beautify_file(filepath, OPTIONS)
res = re.sub(r"\$[\s\n]+\"", '$"', res)
return res


def get_staged_files():
# Run the git command
result = subprocess.run(
["git", "diff", "--name-only", "--cached"],
stdout=subprocess.PIPE, # Capture output
stderr=subprocess.PIPE, # Capture errors
text=True,
) # Return output as string

# Check if there was an error
if result.returncode != 0:
print(f"Error: {result.stderr}")
return []

# Get the output (list of file paths)
staged_files = result.stdout.strip().split("\n")

# Remove any empty strings (in case no files are staged)
return [file for file in staged_files if file]


def get_staged_file_contents(file_path):
try:
# Run the git show command to get the staged contents
result = subprocess.run(
["git", "show", f":{file_path}"], capture_output=True, text=True, check=True
)
return result.stdout # Return the staged file contents
except subprocess.CalledProcessError as e:
print(f"ERROR: {e}")
exit(1)


if __name__ == "__main__":
target = "--staged"
filepath = None

if len(sys.argv) > 1:
target = sys.argv[1]

if target == "--file":
if len(sys.argv) > 2:
filepath = sys.argv[2]
else:
print("Argument FILE not defined!")
print(1)

if target == "-h":
print(HELP_MESSAGE)
elif target == "-v":
print(VERSION_STRING)
elif target == "--validate":
for filepath in get_staged_files():
if filepath.endswith(".gml"):
orig = get_staged_file_contents(filepath)
res = beautify_file(filepath)
if orig != res:
print(
f'ERROR: File "{filepath}" is not properly formatted!\n\nPlease run ./format-gml.py to fix formatting of all staged GML files and stage the changes before running commit again.'
)
exit(1)
elif target == "--staged":
for filepath in get_staged_files():
if filepath.endswith(".gml"):
res = beautify_file(filepath)
with open(filepath, "w") as f:
f.write(res)
elif target == "--all":
for dirpath, _, filenames in os.walk("."):
for filename in filenames:
if filename.endswith(".gml"):
filepath = os.path.join(dirpath, filename)
res = beautify_file(filepath)
with open(filepath, "w") as f:
f.write(res)
elif target == "--file":
res = beautify_file(filepath)
with open(filepath, "w") as f:
f.write(res)
else:
print(f"Invalid target {target}! Run format-gml -h to display usage.")
exit(1)
7 changes: 7 additions & 0 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
if hash python3 2>/dev/null;
then
python3 format-gml.py --validate
else
python format-gml.py --validate
fi
9 changes: 9 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cachetools==5.0.0
EditorConfig==0.12.4
future==0.18.2
Jinja2==3.1.1
jsbeautifier==1.15.1
MarkupSafe==2.1.1
mistune==2.0.2
pefile==2021.9.3
six==1.16.0

0 comments on commit 2cd2d2e

Please sign in to comment.