Skip to content

Commit 073a4a9

Browse files
authored
Merge pull request #24 from rtuszik/develop
v0.5.0
2 parents 170de28 + b2ea8fb commit 073a4a9

File tree

13 files changed

+1319
-1425
lines changed

13 files changed

+1319
-1425
lines changed

.gitignore

Lines changed: 9 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
.aider*
22
output/*
33

4+
5+
*.log
6+
7+
env
8+
venv
9+
.venv
10+
.env
11+
412
cheatsheets/*
513
!cheatsheets/example-cheatsheet.yaml
614

@@ -10,12 +18,6 @@ cheatsheets/*
1018
.AppleDouble
1119
.LSOverride
1220

13-
# Icon must end with two \r
14-
Icon
15-
16-
# Thumbnails
17-
._*
18-
1921
# Files that might appear in the root of a volume
2022
.DocumentRevisions-V100
2123
.fseventsd
@@ -25,25 +27,6 @@ Icon
2527
.VolumeIcon.icns
2628
.com.apple.timemachine.donotpresent
2729

28-
# Directories potentially created on remote AFP share
29-
.AppleDB
30-
.AppleDesktop
31-
Network Trash Folder
32-
Temporary Items
33-
.apdisk
34-
35-
### macOS Patch ###
36-
# iCloud generated files
37-
*.icloud
38-
39-
### Python ###
40-
# Byte-compiled / optimized / DLL files
41-
__pycache__/
42-
*.py[cod]
43-
*$py.class
44-
45-
# C extensions
46-
*.so
4730

4831
# Distribution / packaging
4932
.Python
@@ -65,180 +48,5 @@ share/python-wheels/
6548
*.egg
6649
MANIFEST
6750

68-
# PyInstaller
69-
# Usually these files are written by a python script from a template
70-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
71-
*.manifest
72-
*.spec
73-
74-
# Installer logs
75-
pip-log.txt
76-
pip-delete-this-directory.txt
77-
78-
# Unit test / coverage reports
79-
htmlcov/
80-
.tox/
81-
.nox/
82-
.coverage
83-
.coverage.*
84-
.cache
85-
nosetests.xml
86-
coverage.xml
87-
*.cover
88-
*.py,cover
89-
.hypothesis/
90-
.pytest_cache/
91-
cover/
92-
93-
# Translations
94-
*.mo
95-
*.pot
96-
97-
# Django stuff:
98-
*.log
99-
local_settings.py
100-
db.sqlite3
101-
db.sqlite3-journal
102-
103-
# Flask stuff:
104-
instance/
105-
.webassets-cache
106-
107-
# Scrapy stuff:
108-
.scrapy
109-
110-
# Sphinx documentation
111-
docs/_build/
112-
113-
# PyBuilder
114-
.pybuilder/
115-
target/
116-
117-
# Jupyter Notebook
118-
.ipynb_checkpoints
119-
120-
# IPython
121-
profile_default/
122-
ipython_config.py
123-
124-
# pyenv
125-
# For a library or package, you might want to ignore these files since the code is
126-
# intended to run in multiple environments; otherwise, check them in:
127-
# .python-version
128-
129-
# pipenv
130-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
131-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
132-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
133-
# install all needed dependencies.
134-
#Pipfile.lock
135-
136-
# poetry
137-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
138-
# This is especially recommended for binary packages to ensure reproducibility, and is more
139-
# commonly ignored for libraries.
140-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
141-
#poetry.lock
142-
143-
# pdm
144-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
145-
#pdm.lock
146-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
147-
# in version control.
148-
# https://pdm.fming.dev/#use-with-ide
149-
.pdm.toml
150-
151-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
152-
__pypackages__/
153-
154-
# Celery stuff
155-
celerybeat-schedule
156-
celerybeat.pid
157-
158-
# SageMath parsed files
159-
*.sage.py
160-
161-
# Environments
162-
.env
163-
.venv
164-
env/
165-
venv/
166-
ENV/
167-
env.bak/
168-
venv.bak/
169-
170-
# Spyder project settings
171-
.spyderproject
172-
.spyproject
173-
174-
# Rope project settings
175-
.ropeproject
176-
177-
# mkdocs documentation
178-
/site
179-
180-
# mypy
181-
.mypy_cache/
182-
.dmypy.json
183-
dmypy.json
184-
185-
# Pyre type checker
186-
.pyre/
187-
188-
# pytype static type analyzer
189-
.pytype/
190-
191-
# Cython debug symbols
192-
cython_debug/
193-
194-
# PyCharm
195-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
196-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
197-
# and can be added to the global gitignore or merged into this file. For a more nuclear
198-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
199-
#.idea/
200-
201-
### Python Patch ###
202-
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
203-
poetry.toml
204-
205-
# ruff
206-
.ruff_cache/
207-
208-
# LSP config files
209-
pyrightconfig.json
210-
211-
### venv ###
212-
# Virtualenv
213-
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
214-
[Bb]in
215-
[Ii]nclude
216-
[Ll]ib
217-
[Ll]ib64
218-
[Ll]ocal
219-
[Ss]cripts
220-
pyvenv.cfg
221-
pip-selfcheck.json
222-
223-
### Vim ###
224-
# Swap
225-
[._]*.s[a-v][a-z]
226-
!*.svg # comment out if you don't need vector files
227-
[._]*.sw[a-p]
228-
[._]s[a-rt-v][a-z]
229-
[._]ss[a-gi-z]
230-
[._]sw[a-p]
231-
232-
# Session
233-
Session.vim
234-
Sessionx.vim
235-
236-
# Temporary
237-
.netrwhist
238-
*~
239-
# Auto-generated tag files
240-
tags
241-
# Persistent undo
242-
[._]*.un~
24351

244-
# End of https://www.toptal.com/developers/gitignore/api/Vim,macOS,Python,venv
52+
*pycache*

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
pyyaml==6.0.2
21
jinja2==3.1.4
32
python-dotenv==1.0.1
43
ruamel.yaml==0.18.6

src/__init__.py

Whitespace-only changes.

src/generate_cheatsheet.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import yaml
1+
from ruamel.yaml import YAML
22
from jinja2 import Environment, FileSystemLoader
33
import sys
44
import os
@@ -8,6 +8,13 @@
88
from logger import get_logger
99
from pathlib import Path
1010

11+
# Create YAML instances once
12+
yaml_safe = YAML(typ='safe')
13+
yaml_rw = YAML()
14+
yaml_rw.indent(mapping=2, sequence=4, offset=2)
15+
yaml_rw.preserve_quotes = True
16+
yaml_rw.width = 100
17+
1118
load_dotenv()
1219

1320
# Define base paths
@@ -29,16 +36,13 @@
2936

3037
def load_yaml(file_path: Path) -> dict | None:
3138
try:
32-
with open(file_path, "r") as file:
33-
return yaml.safe_load(file)
39+
with open(file_path, "r", encoding='utf-8') as file:
40+
return yaml_safe.load(file)
3441
except FileNotFoundError:
3542
logging.error(f"Error: YAML file '{file_path}' not found.")
3643
return None
37-
except yaml.YAMLError as e:
38-
logging.error(f"Error parsing YAML file '{file_path}': {e}")
39-
return None
4044
except Exception as e:
41-
logging.error(f"Unexpected error reading file '{file_path}': {e}")
45+
logging.error(f"Error reading YAML file '{file_path}': {e}")
4246
return None
4347

4448

@@ -119,9 +123,8 @@ def get_layout_info(data):
119123
"system": layout.get("system", "Darwin"),
120124
}
121125

122-
123126
def generate_html(data, keyboard_layouts, system_mappings):
124-
template_path = TEMPLATES_DIR / "cheatsheet_template.html"
127+
template_path = "cheatsheets/cheatsheet-template.html"
125128
layout_info = get_layout_info(data)
126129
data["shortcuts"] = normalize_shortcuts(
127130
data, system_mappings.get(layout_info["system"], {})
@@ -135,13 +138,11 @@ def generate_html(data, keyboard_layouts, system_mappings):
135138

136139

137140
def validate_and_lint(yaml_file):
138-
errors = validate_yaml(yaml_file)
141+
validation_result = validate_yaml(yaml_file)
139142
warnings = lint_yaml(yaml_file)
140143

141-
if errors:
142-
logging.error(f"Validation errors in {yaml_file}:")
143-
for error in errors:
144-
logging.error(f" - {error}")
144+
if not validation_result:
145+
logging.error(f"Validation failed for {yaml_file}")
145146
return False
146147

147148
if warnings:
@@ -153,7 +154,7 @@ def validate_and_lint(yaml_file):
153154

154155
def write_html_content(html_output, html_content):
155156
try:
156-
with open(html_output, "w") as file:
157+
with open(html_output, "w", encoding='utf-8') as file:
157158
file.write(html_content)
158159
except IOError as e:
159160
logging.error(f"Error writing to output file: {e}")
@@ -197,7 +198,7 @@ def generate_index(cheatsheets):
197198

198199
index_output = os.path.join(OUTPUT_DIR, "index.html")
199200

200-
with open(index_output, "w") as file:
201+
with open(index_output, "w", encoding='utf-8') as file:
201202
file.write(html_content)
202203

203204
logging.info(f"Index page generated: {index_output}")

src/template_renderer.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1-
from jinja2 import Template
1+
from jinja2 import Environment, FileSystemLoader
22
from logger import get_logger
3+
from pathlib import Path
34

45
logging = get_logger()
56

67
def render_template(template_path, data):
8+
"""
9+
Render a template from the given path with provided data.
10+
"""
711
try:
8-
with open(template_path, "r") as file:
9-
template = Template(file.read())
12+
# Use the templates directory directly
13+
templates_dir = Path(__file__).parent / "templates"
14+
15+
env = Environment(
16+
loader=FileSystemLoader(str(templates_dir))
17+
)
18+
19+
template = env.get_template(str(template_path))
20+
return template.render(**data)
21+
1022
except FileNotFoundError:
1123
logging.error(f"Error: Template file '{template_path}' not found.")
1224
return None
1325
except Exception as e:
1426
logging.error(f"Error reading template file: {e}")
1527
return None
1628

17-
try:
18-
return template.render(**data)
19-
except Exception as e:
20-
logging.error(f"Error rendering template: {e}")
21-
return None

src/templates/base.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en" charset="UTF-8">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
{% block header %}{% endblock %}
7+
<title>
8+
{% block title %}{% endblock %}
9+
</title>
10+
{% block page_styles %}{% endblock %}
11+
</head>
12+
<body class="dark-mode">
13+
{% block content %}{% endblock %}
14+
{% block javascript %}{% endblock %}
15+
</body>
16+
</html>

0 commit comments

Comments
 (0)