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.
- hyprconf2lua/__init__.py +1 -0
- hyprconf2lua/__main__.py +4 -0
- hyprconf2lua/ast.py +171 -0
- hyprconf2lua/cli.py +173 -0
- hyprconf2lua/codegen.py +931 -0
- hyprconf2lua/converter.py +60 -0
- hyprconf2lua/lexer.py +74 -0
- hyprconf2lua/mappings.py +130 -0
- hyprconf2lua/parser.py +494 -0
- hyprconf2lua-1.2.0.dist-info/METADATA +242 -0
- hyprconf2lua-1.2.0.dist-info/RECORD +15 -0
- hyprconf2lua-1.2.0.dist-info/WHEEL +5 -0
- hyprconf2lua-1.2.0.dist-info/entry_points.txt +2 -0
- hyprconf2lua-1.2.0.dist-info/licenses/LICENSE +21 -0
- hyprconf2lua-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Dict, Optional, Tuple
|
|
3
|
+
|
|
4
|
+
from hyprconf2lua.lexer import tokenize, LexerError
|
|
5
|
+
from hyprconf2lua.parser import parse_config, ParserError
|
|
6
|
+
from hyprconf2lua.codegen import Codegen
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConversionError(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ConversionResult:
|
|
14
|
+
def __init__(self, lua: str, report: dict, errors: list, warnings: list):
|
|
15
|
+
self.lua = lua
|
|
16
|
+
self.report = report
|
|
17
|
+
self.errors = errors
|
|
18
|
+
self.warnings = warnings
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def success(self) -> bool:
|
|
22
|
+
return len(self.errors) == 0
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def coverage(self) -> float:
|
|
26
|
+
total = self.report.get("translated", 0) + self.report.get("passthrough", 0) + self.report.get("flagged", 0)
|
|
27
|
+
if total == 0:
|
|
28
|
+
return 100.0
|
|
29
|
+
return round(self.report.get("translated", 0) / total * 100, 1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def convert(source: str) -> ConversionResult:
|
|
33
|
+
errors: list = []
|
|
34
|
+
warnings: list = []
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
tokens = tokenize(source)
|
|
38
|
+
except LexerError as e:
|
|
39
|
+
errors.append(str(e))
|
|
40
|
+
return ConversionResult("", {"translated": 0, "passthrough": 0, "flagged": 0}, errors, warnings)
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
config = parse_config(source)
|
|
44
|
+
except ParserError as e:
|
|
45
|
+
errors.append(str(e))
|
|
46
|
+
return ConversionResult("", {"translated": 0, "passthrough": 0, "flagged": 0}, errors, warnings)
|
|
47
|
+
|
|
48
|
+
gen = Codegen()
|
|
49
|
+
try:
|
|
50
|
+
lua = gen.generate(config)
|
|
51
|
+
except Exception as e:
|
|
52
|
+
errors.append(f"Code generation error: {e}")
|
|
53
|
+
return ConversionResult("", {"translated": 0, "passthrough": 0, "flagged": 0}, errors, warnings)
|
|
54
|
+
|
|
55
|
+
report = gen.get_report()
|
|
56
|
+
|
|
57
|
+
if report["flagged"] > 0:
|
|
58
|
+
warnings.append(f"{report['flagged']} directive(s) flagged for manual review")
|
|
59
|
+
|
|
60
|
+
return ConversionResult(lua, report, errors, warnings)
|
hyprconf2lua/lexer.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import re
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
TOKEN_SPECS = [
|
|
8
|
+
("COMMENT", r"#[^\n]*"),
|
|
9
|
+
("BLOCK_OPEN", r"\{"),
|
|
10
|
+
("BLOCK_CLOSE", r"\}"),
|
|
11
|
+
("EQUALS", r"="),
|
|
12
|
+
("COMMA", r","),
|
|
13
|
+
("DOT", r"\."),
|
|
14
|
+
("COLON", r":"),
|
|
15
|
+
("DOLLAR", r"\$"),
|
|
16
|
+
("STRING", r'"([^"\\]|\\.)*"'),
|
|
17
|
+
("IDENT", r'[^\s#"={},:!]+'),
|
|
18
|
+
("NEWLINE", r"\n"),
|
|
19
|
+
("SKIP", r"[ \t]+"),
|
|
20
|
+
("MISMATCH", r"."),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Token:
|
|
26
|
+
type: str
|
|
27
|
+
value: str
|
|
28
|
+
line: int
|
|
29
|
+
col: int
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
return f"Token({self.type}, {self.value!r}, L{self.line}:{self.col})"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
TOKEN_REGEX = re.compile("|".join(f"(?P<{name}>{pattern})" for name, pattern in TOKEN_SPECS))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LexerError(Exception):
|
|
39
|
+
def __init__(self, message: str, line: int, col: int):
|
|
40
|
+
self.line = line
|
|
41
|
+
self.col = col
|
|
42
|
+
super().__init__(f"L{line}:{col}: {message}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def tokenize(source: str) -> List[Token]:
|
|
46
|
+
tokens: List[Token] = []
|
|
47
|
+
line = 1
|
|
48
|
+
last_line_start = 0
|
|
49
|
+
|
|
50
|
+
def _col(pos: int) -> int:
|
|
51
|
+
return pos - last_line_start + 1
|
|
52
|
+
|
|
53
|
+
for m in TOKEN_REGEX.finditer(source):
|
|
54
|
+
kind = m.lastgroup
|
|
55
|
+
value = m.group()
|
|
56
|
+
pos = m.start()
|
|
57
|
+
|
|
58
|
+
if kind == "NEWLINE":
|
|
59
|
+
line += 1
|
|
60
|
+
last_line_start = pos + 1
|
|
61
|
+
tokens.append(Token("NEWLINE", value, line - 1, _col(pos)))
|
|
62
|
+
elif kind == "SKIP":
|
|
63
|
+
pass
|
|
64
|
+
elif kind == "COMMENT":
|
|
65
|
+
tokens.append(Token("COMMENT", value, line, _col(pos)))
|
|
66
|
+
elif kind == "MISMATCH":
|
|
67
|
+
raise LexerError(f"Unexpected character: {value!r}", line, _col(pos))
|
|
68
|
+
elif kind == "STRING":
|
|
69
|
+
tokens.append(Token("STRING", value[1:-1], line, _col(pos)))
|
|
70
|
+
else:
|
|
71
|
+
tokens.append(Token(kind, value, line, _col(pos)))
|
|
72
|
+
|
|
73
|
+
tokens.append(Token("EOF", "", line, 1))
|
|
74
|
+
return tokens
|
hyprconf2lua/mappings.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
DISPATCHER_MAP = {
|
|
2
|
+
"exec": ("hl.dsp.exec_cmd", True),
|
|
3
|
+
"execr": ("hl.dsp.exec_raw", True),
|
|
4
|
+
"killactive": ("hl.dsp.window.close", False),
|
|
5
|
+
"kill": ("hl.dsp.window.kill", False),
|
|
6
|
+
"exit": ("hl.dsp.exit", False),
|
|
7
|
+
"fullscreen": ("hl.dsp.window.fullscreen", False),
|
|
8
|
+
"fullscreenstate": ("hl.dsp.window.fullscreen_state", True),
|
|
9
|
+
"togglefloating": ("hl.dsp.window.float", False),
|
|
10
|
+
"setfloating": ("hl.dsp.window.float", True),
|
|
11
|
+
"pseudo": ("hl.dsp.window.pseudo", False),
|
|
12
|
+
"togglesplit": ("hl.dsp.layout", True),
|
|
13
|
+
"layoutmsg": ("hl.dsp.layout", True),
|
|
14
|
+
"cyclenext": ("hl.dsp.window.cycle_next", False),
|
|
15
|
+
"focuswindow": ("hl.dsp.focus", True),
|
|
16
|
+
"focuscurrentorlast":("hl.dsp.focus", True),
|
|
17
|
+
"movefocus": ("hl.dsp.focus", True),
|
|
18
|
+
"movewindow": ("hl.dsp.window.move", True),
|
|
19
|
+
"swapwindow": ("hl.dsp.window.swap", True),
|
|
20
|
+
"swapnext": ("hl.dsp.window.swap", True),
|
|
21
|
+
"centerwindow": ("hl.dsp.window.center", False),
|
|
22
|
+
"resizewindow": ("hl.dsp.window.resize", True),
|
|
23
|
+
"movecursor": ("hl.dsp.cursor.move", True),
|
|
24
|
+
"pin": ("hl.dsp.window.pin", False),
|
|
25
|
+
"tag": ("hl.dsp.window.tag", True),
|
|
26
|
+
"togglegroup": ("hl.dsp.group.toggle", False),
|
|
27
|
+
"changegroupactive": ("hl.dsp.group.next", False),
|
|
28
|
+
"focusgroupwindow": ("hl.dsp.group.active", True),
|
|
29
|
+
"movegroupwindow": ("hl.dsp.group.move_window", True),
|
|
30
|
+
"lockgroups": ("hl.dsp.group.lock", False),
|
|
31
|
+
"workspace": ("hl.dsp.focus", True),
|
|
32
|
+
"movetoworkspace": ("hl.dsp.window.move", True),
|
|
33
|
+
"movetoworkspacesilent": ("hl.dsp.window.move", True),
|
|
34
|
+
"focusmonitor": ("hl.dsp.focus", True),
|
|
35
|
+
"movetomonitor": ("hl.dsp.window.move", True),
|
|
36
|
+
"togglespecialworkspace": ("hl.dsp.workspace.toggle_special", True),
|
|
37
|
+
"renameworkspace": ("hl.dsp.workspace.rename", True),
|
|
38
|
+
"alterzorder": ("hl.dsp.window.alter_zorder", True),
|
|
39
|
+
"setprop": ("hl.dsp.window.set_prop", True),
|
|
40
|
+
"swallows": ("hl.dsp.window.toggle_swallow", False),
|
|
41
|
+
"denywindowfromgroup":("hl.dsp.window.deny_from_group", False),
|
|
42
|
+
"submap": ("hl.dsp.submap", True),
|
|
43
|
+
"pass": ("hl.dsp.pass", True),
|
|
44
|
+
"sendshortcut": ("hl.dsp.send_shortcut", True),
|
|
45
|
+
"dpms": ("hl.dsp.dpms", True),
|
|
46
|
+
"noop": ("hl.dsp.no_op", False),
|
|
47
|
+
"event": ("hl.dsp.event", True),
|
|
48
|
+
"global": ("hl.dsp.global", True),
|
|
49
|
+
"forceidle": ("hl.dsp.force_idle", True),
|
|
50
|
+
"moveintogroup": ("hl.dsp.window.move", True),
|
|
51
|
+
"moveoutofgroup": ("hl.dsp.window.move", True),
|
|
52
|
+
"focusurgentorlast": ("hl.dsp.focus", True),
|
|
53
|
+
"focusonemonitor": ("hl.dsp.focus", True),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
BIND_FLAGS_TO_OPTIONS = {
|
|
57
|
+
"l": ("locked", "true"),
|
|
58
|
+
"r": ("repeating", "true"),
|
|
59
|
+
"n": ("non_consuming", "true"),
|
|
60
|
+
"m": ("mouse", "true"),
|
|
61
|
+
"e": ("empty", "true"),
|
|
62
|
+
"t": ("transparent", "true"),
|
|
63
|
+
"i": ("ignore_mods", "true"),
|
|
64
|
+
"p": ("pass", "true"),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
WINDOW_RULE_MAP = {
|
|
68
|
+
"float": ("float", "true"),
|
|
69
|
+
"tile": ("tile", "true"),
|
|
70
|
+
"pin": ("pin", "true"),
|
|
71
|
+
"nofocus": ("no_focus", "true"),
|
|
72
|
+
"noborder": ("border", "false"),
|
|
73
|
+
"noblur": ("blur", "false"),
|
|
74
|
+
"noshadow": ("shadow", "false"),
|
|
75
|
+
"noanim": ("no_anim", "true"),
|
|
76
|
+
"dimaround": ("dim_around", "true"),
|
|
77
|
+
"noblur": ("blur", "false"),
|
|
78
|
+
"noshadow": ("shadow", "false"),
|
|
79
|
+
"nomaxsize": ("max_size", "false"),
|
|
80
|
+
"fakefullscreen": ("fake_fullscreen", "true"),
|
|
81
|
+
"noinitialfocus": ("no_initial_focus", "true"),
|
|
82
|
+
"windowdance": ("window_dance", "true"),
|
|
83
|
+
"nofullscreenrequests": ("suppress_event", "fullscreen"),
|
|
84
|
+
"nomaximizerequest": ("suppress_event", "maximize"),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
WINDOW_RULE_PARAM_MAP = {
|
|
88
|
+
"opacity": ("opacity", True),
|
|
89
|
+
"alpha": ("alpha", True),
|
|
90
|
+
"border_size": ("border_size", True),
|
|
91
|
+
"rounding": ("rounding", True),
|
|
92
|
+
"monitor": ("monitor", True),
|
|
93
|
+
"workspace": ("workspace", True),
|
|
94
|
+
"move": ("move", True),
|
|
95
|
+
"size": ("size", True),
|
|
96
|
+
"minsize": ("min_size", True),
|
|
97
|
+
"maxsize": ("max_size", True),
|
|
98
|
+
"maxsize": ("max_size", True),
|
|
99
|
+
"idleinhibit": ("idle_inhibit", True),
|
|
100
|
+
"xray": ("xray", True),
|
|
101
|
+
"center": ("center", True),
|
|
102
|
+
"keepaspectratio": ("keep_aspect_ratio", "true"),
|
|
103
|
+
"dimaround": ("dim_around", "true"),
|
|
104
|
+
"fullscreen": ("fullscreen", True),
|
|
105
|
+
"maximize": ("maximize", True),
|
|
106
|
+
"suppressevent": ("suppress_event", True),
|
|
107
|
+
"pseudo": ("pseudo", "true"),
|
|
108
|
+
"stayfocused": ("stay_focused", "true"),
|
|
109
|
+
"group": ("group", True),
|
|
110
|
+
"scroll_touchpad": ("scroll_touchpad", True),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
WORKSPACE_RULE_MAP = {
|
|
114
|
+
"monitor": "monitor",
|
|
115
|
+
"default": "is_default",
|
|
116
|
+
"gapsin": "gaps_in",
|
|
117
|
+
"gapsout": "gaps_out",
|
|
118
|
+
"bordersize": "border_size",
|
|
119
|
+
"rounding": "rounding",
|
|
120
|
+
"decorate": "decorate",
|
|
121
|
+
"persistent": "persistent",
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
LAYER_RULE_MAP = {
|
|
125
|
+
"blur": ("blur", "true"),
|
|
126
|
+
"ignorealpha": ("ignore_alpha", True),
|
|
127
|
+
"ignorezero": ("ignore_alpha", True),
|
|
128
|
+
"noanim": ("no_anim", "true"),
|
|
129
|
+
"noblur": ("blur", "false"),
|
|
130
|
+
}
|