hyprconf2lua 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,4 @@
1
+ from hyprconf2lua.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
hyprconf2lua/ast.py ADDED
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass, field
3
+ from typing import Dict, List, Optional, Union
4
+
5
+
6
+ Value = Union[str, List["Value"]]
7
+
8
+
9
+ @dataclass
10
+ class Comment:
11
+ text: str
12
+ line: int
13
+
14
+ def __str__(self) -> str:
15
+ return self.text
16
+
17
+
18
+ @dataclass
19
+ class Directive:
20
+ key: str
21
+ value: List[str]
22
+ line: int
23
+ col: int
24
+
25
+
26
+ @dataclass
27
+ class Section:
28
+ name: str
29
+ body: Block
30
+ line: int
31
+
32
+
33
+ @dataclass
34
+ class VariableDef:
35
+ name: str
36
+ value: str
37
+ line: int
38
+
39
+
40
+ @dataclass
41
+ class ExecDirective:
42
+ kind: str
43
+ command: str
44
+ line: int
45
+
46
+
47
+ @dataclass
48
+ class BindDirective:
49
+ mods: List[str]
50
+ key: str
51
+ dispatcher: str
52
+ params: List[str]
53
+ flags: str
54
+ line: int
55
+
56
+
57
+ @dataclass
58
+ class MonitorDirective:
59
+ name: str
60
+ mode: str
61
+ position: str
62
+ scale: str
63
+ line: int
64
+ extra: Dict[str, str] = field(default_factory=dict)
65
+
66
+
67
+ @dataclass
68
+ class WindowRule:
69
+ is_v2: bool
70
+ rule: str
71
+ match_params: List[str]
72
+ line: int
73
+
74
+
75
+ @dataclass
76
+ class AnimationDirective:
77
+ name: str
78
+ style: str
79
+ speed: str
80
+ curve: str
81
+ line: int
82
+
83
+
84
+ @dataclass
85
+ class BezierDirective:
86
+ name: str
87
+ p1x: str
88
+ p1y: str
89
+ p2x: str
90
+ p2y: str
91
+ line: int
92
+
93
+
94
+ @dataclass
95
+ class EnvDirective:
96
+ name: str
97
+ value: str
98
+ line: int
99
+
100
+
101
+ @dataclass
102
+ class SourceDirective:
103
+ path: str
104
+ line: int
105
+
106
+
107
+ @dataclass
108
+ class DeviceSection:
109
+ name: str
110
+ body: List[Directive]
111
+ line: int
112
+
113
+
114
+ @dataclass
115
+ class GestureDirective:
116
+ body: List[Directive]
117
+ line: int
118
+
119
+
120
+ @dataclass
121
+ class WorkspaceDirective:
122
+ name: str
123
+ params: List[str]
124
+ line: int
125
+
126
+
127
+ @dataclass
128
+ class LayerRuleDirective:
129
+ rule: str
130
+ namespace: str
131
+ line: int
132
+
133
+
134
+ @dataclass
135
+ class SubmapDef:
136
+ name: str
137
+ body: List[BlockStmt]
138
+ line: int
139
+
140
+
141
+ @dataclass
142
+ class WindowRuleBlock:
143
+ is_v2: bool
144
+ name: str
145
+ match: Dict[str, str]
146
+ effects: Dict[str, List[str]]
147
+ line: int
148
+
149
+
150
+ @dataclass
151
+ class LayerRuleBlock:
152
+ name: str
153
+ match: Dict[str, str]
154
+ effects: Dict[str, List[str]]
155
+ line: int
156
+
157
+
158
+ BlockStmt = Union[
159
+ Directive, Section, VariableDef, ExecDirective, BindDirective,
160
+ MonitorDirective, WindowRule, AnimationDirective, BezierDirective,
161
+ EnvDirective, SourceDirective, DeviceSection, GestureDirective,
162
+ WorkspaceDirective, LayerRuleDirective, SubmapDef, Comment,
163
+ WindowRuleBlock, LayerRuleBlock,
164
+ ]
165
+
166
+ Block = List[BlockStmt]
167
+
168
+
169
+ @dataclass
170
+ class ConfigFile:
171
+ body: Block
hyprconf2lua/cli.py ADDED
@@ -0,0 +1,173 @@
1
+ from __future__ import annotations
2
+ import argparse
3
+ import os
4
+ import sys
5
+
6
+ from hyprconf2lua.converter import convert
7
+
8
+
9
+ def convert_file(path: str, check: bool = False, report: bool = False) -> bool:
10
+ try:
11
+ with open(path, "r") as f:
12
+ source = f.read()
13
+ except FileNotFoundError:
14
+ print(f"Error: file not found: {path}", file=sys.stderr)
15
+ return False
16
+ except IOError as e:
17
+ print(f"Error: {e}", file=sys.stderr)
18
+ return False
19
+
20
+ result = convert(source)
21
+
22
+ if result.errors:
23
+ for err in result.errors:
24
+ print(f"Error: {err}", file=sys.stderr)
25
+ return False
26
+
27
+ if result.warnings:
28
+ for w in result.warnings:
29
+ print(f"Warning: {w}", file=sys.stderr)
30
+
31
+ if check:
32
+ if result.report["flagged"] > 0:
33
+ print(f"Check FAILED: {result.report['flagged']} flagged directives",
34
+ file=sys.stderr)
35
+ return False
36
+ return True
37
+
38
+ return result.lua
39
+
40
+
41
+ def process_dir(dir_path: str, in_place: bool = False, check: bool = False,
42
+ report: bool = False) -> int:
43
+ failed = 0
44
+ for root, dirs, files in os.walk(dir_path):
45
+ for fname in files:
46
+ if not fname.endswith(".conf"):
47
+ continue
48
+ fpath = os.path.join(root, fname)
49
+ lua_path = os.path.splitext(fpath)[0] + ".lua"
50
+
51
+ if not check and not in_place:
52
+ continue
53
+
54
+ lua_output = convert_file(fpath, check=check, report=report)
55
+ if lua_output is False:
56
+ failed += 1
57
+ if check:
58
+ print(f" FAIL: {fpath}", file=sys.stderr)
59
+ continue
60
+
61
+ if isinstance(lua_output, str):
62
+ if check:
63
+ print(f" PASS: {fpath}")
64
+ continue
65
+ if in_place:
66
+ try:
67
+ with open(lua_path, "w") as f:
68
+ f.write(lua_output)
69
+ print(f" WROTE: {lua_path}")
70
+ except IOError as e:
71
+ print(f" ERROR writing {lua_path}: {e}", file=sys.stderr)
72
+ failed += 1
73
+
74
+ return failed
75
+
76
+
77
+ def main():
78
+ parser = argparse.ArgumentParser(
79
+ description="Convert Hyprland hyprlang .conf to Lua .lua config (v0.55+)",
80
+ formatter_class=argparse.RawDescriptionHelpFormatter,
81
+ epilog="""
82
+ Examples:
83
+ hyprconf2lua hyprland.conf > hyprland.lua
84
+ hyprconf2lua --in hyprland.conf --out hyprland.lua
85
+ hyprconf2lua --dir ~/.config/hypr --in-place
86
+ cat hyprland.conf | hyprconf2lua > hyprland.lua
87
+ hyprconf2lua --check hyprland.conf
88
+ """,
89
+ )
90
+ parser.add_argument("file", nargs="?", help="Input .conf file (reads stdin if omitted)")
91
+ parser.add_argument("-o", "--out", help="Output file (default: stdout)")
92
+ parser.add_argument("-d", "--dir", help="Walk a directory, writing .lua next to each .conf")
93
+ parser.add_argument("--in-place", action="store_true", help="With --dir, overwrite existing .lua siblings")
94
+ parser.add_argument("--check", action="store_true", help="Exit 3 if any directive is flagged")
95
+ parser.add_argument("--report", action="store_true", help="Print translation stats to stderr")
96
+ parser.add_argument("--version", action="store_true", help="Print version and exit")
97
+
98
+ args = parser.parse_args()
99
+
100
+ if args.version:
101
+ from hyprconf2lua import __version__
102
+ print(f"hyprconf2lua v{__version__}")
103
+ sys.exit(0)
104
+
105
+ if args.dir:
106
+ failed = process_dir(args.dir, in_place=args.in_place, check=args.check, report=args.report)
107
+ if args.check and failed > 0:
108
+ sys.exit(3)
109
+ sys.exit(1 if failed > 0 else 0)
110
+
111
+ source: str
112
+ source_name: str = args.file or "stdin"
113
+
114
+ if args.file:
115
+ try:
116
+ with open(args.file, "r") as f:
117
+ source = f.read()
118
+ except FileNotFoundError:
119
+ print(f"Error: file not found: {args.file}", file=sys.stderr)
120
+ sys.exit(1)
121
+ except IOError as e:
122
+ print(f"Error reading {args.file}: {e}", file=sys.stderr)
123
+ sys.exit(1)
124
+ else:
125
+ if sys.stdin.isatty():
126
+ parser.print_help()
127
+ sys.exit(0)
128
+ source = sys.stdin.read()
129
+
130
+ result = convert(source)
131
+
132
+ for err in result.errors:
133
+ print(f"Error: {err}", file=sys.stderr)
134
+
135
+ if result.errors:
136
+ sys.exit(1)
137
+
138
+ for w in result.warnings:
139
+ print(f"Warning: {w}", file=sys.stderr)
140
+
141
+ if not result.lua.strip():
142
+ print("Error: conversion produced no output", file=sys.stderr)
143
+ sys.exit(1)
144
+
145
+ if args.report:
146
+ r = result.report
147
+ total = r["translated"] + r["passthrough"] + r["flagged"]
148
+ cov = result.coverage
149
+ print(f"Report: {r['translated']} translated, {r['passthrough']} passthrough, "
150
+ f"{r['flagged']} flagged, {total} total, {cov}% coverage",
151
+ file=sys.stderr)
152
+
153
+ if args.check:
154
+ if result.report["flagged"] > 0:
155
+ print(f"Check FAILED: {result.report['flagged']} flagged directive(s)",
156
+ file=sys.stderr)
157
+ sys.exit(3)
158
+ sys.exit(0)
159
+
160
+ if args.out:
161
+ try:
162
+ with open(args.out, "w") as f:
163
+ f.write(result.lua)
164
+ except IOError as e:
165
+ print(f"Error writing {args.out}: {e}", file=sys.stderr)
166
+ sys.exit(1)
167
+ else:
168
+ sys.stdout.write(result.lua)
169
+ sys.stdout.flush()
170
+
171
+
172
+ if __name__ == "__main__":
173
+ main()