forked from exciting-IRC/IRC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
create.py
executable file
·110 lines (77 loc) · 3.01 KB
/
create.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
"""
create.py: create boilerplate for *.cpp, *.hpp, *.tpp
usage:
create.py [-h] [options] [-n | -N | --namespace <N> ] <path>
options:
-h, --help show this help message and exit
-n use parent directory name as namespace
-N use nested directory names as namespace
--namespace <N> choose namespace to use.
-r <R>, --root <R> root of directory path [default: src]
"""
from __future__ import annotations
from pathlib import Path
from sys import argv
from typing import Optional
from docopt import docopt
def wrap_with(body: str, wrap: tuple[str, str], *, distance: int = 1) -> str:
nl = distance * "\n"
return f"{wrap[0]}{nl}{body}{nl}{wrap[1]}"
def wrap_header(body: str, path: Path) -> str:
guard = "_".join(path.parts).replace(".", "_").upper()
header = (
f"#ifndef {guard}\n" f"#define {guard}",
f"#endif // {guard}",
)
return wrap_with(body, header, distance=2)
def base_category_name(stem: str) -> str:
return stem.rsplit("_", maxsplit=1)[0]
def remove_prefix(text: str, prefix: str) -> str:
"because cluster python is 3.8 and no str.removeprefix()"
return text[len(prefix) :] if text.startswith(prefix) else text
def get_include(path: Path) -> str:
if path.suffix == ".hpp":
return ""
elif path.suffix == ".tpp":
name = base_category_name(path.stem)
elif path.suffix == ".cpp":
name = remove_prefix(path.parent.stem, "lib")
else:
raise ValueError(f"Unknown file type: {path}")
return f"#include <{'/'.join(path.parent.parts)}/{name}.hpp>"
def get_nested_namespace(names: tuple[str]) -> str:
names = tuple(remove_prefix(n, "lib") for n in names)
begins = "\n".join([f"namespace {ns} {{" for ns in names])
ends = "\n".join([f"}} // namespace {ns}" for ns in reversed(names)])
return f"{begins}\n{ends}"
def save_text_to(text: str, path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(f"{text}\n")
print(text)
def create_text(path: Path, *, namespace: Optional[tuple[str]]) -> str:
text = get_include(path)
if namespace:
text += f"\n\n{get_nested_namespace(namespace)}"
return text if path.suffix == ".cpp" else wrap_header(text, path)
def get_namespace(path: Path, args: dict[str, str]) -> Optional[tuple[str]]:
if namespace := args["--namespace"]:
return (namespace,)
elif args["-n"]:
return (path.parent.stem,)
elif args["-N"]:
return tuple(path.parent.parts)
def main():
assert __doc__ is not None
args: dict[str, str] = docopt(__doc__)
# print(args)
path = Path(args["<path>"])
fullpath = Path(__file__).parent / args["--root"] / args["<path>"]
if fullpath.exists():
print("file already exists")
return
namespace = get_namespace(path, args)
text = create_text(path, namespace=namespace)
save_text_to(text, fullpath)
if __name__ == "__main__":
main()