Skip to content

Commit

Permalink
feat(shortcuts): generate shortcut actions from source
Browse files Browse the repository at this point in the history
- Add generator for shortcut-actions.json from COSMIC source code
- Add rustToNixType utility function for type conversion
- Refactor shortcuts module to use generated actions
- Remove hardcoded shortcut actions list
  • Loading branch information
HeitorAugustoLN committed Dec 29, 2024
1 parent fcd1ba9 commit 4ec258d
Show file tree
Hide file tree
Showing 6 changed files with 521 additions and 194 deletions.
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
formatter = pkgs.treefmt;

packages = {
generate-shortcut-actions = pkgs.callPackage ./generators/shortcut-actions { };

home-manager-options = mkOptionsDoc {
inherit version;
moduleRoot = ./modules;
Expand Down
260 changes: 260 additions & 0 deletions generated/shortcut-actions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
{
"Actions": [
{
"name": "Close"
},
{
"name": "Debug"
},
{
"name": "Disable"
},
{
"name": "Focus",
"type": "FocusDirection"
},
{
"name": "LastWorkspace"
},
{
"name": "Maximize"
},
{
"name": "MigrateWorkspaceToNextOutput"
},
{
"name": "MigrateWorkspaceToOutput",
"type": "Direction"
},
{
"name": "MigrateWorkspaceToPreviousOutput"
},
{
"name": "Minimize"
},
{
"name": "Move",
"type": "Direction"
},
{
"name": "MoveToLastWorkspace"
},
{
"name": "MoveToNextOutput"
},
{
"name": "MoveToNextWorkspace"
},
{
"name": "MoveToOutput",
"type": "Direction"
},
{
"name": "MoveToPreviousOutput"
},
{
"name": "MoveToPreviousWorkspace"
},
{
"name": "MoveToWorkspace",
"type": "u8"
},
{
"name": "NextOutput"
},
{
"name": "NextWorkspace"
},
{
"name": "Orientation",
"type": "Orientation"
},
{
"name": "PreviousOutput"
},
{
"name": "PreviousWorkspace"
},
{
"name": "Resizing",
"type": "ResizeDirection"
},
{
"name": "SendToLastWorkspace"
},
{
"name": "SendToNextOutput"
},
{
"name": "SendToNextWorkspace"
},
{
"name": "SendToOutput",
"type": "Direction"
},
{
"name": "SendToPreviousOutput"
},
{
"name": "SendToPreviousWorkspace"
},
{
"name": "SendToWorkspace",
"type": "u8"
},
{
"name": "SwapWindow"
},
{
"name": "SwitchOutput",
"type": "Direction"
},
{
"name": "System",
"type": "System"
},
{
"name": "Spawn",
"type": "String"
},
{
"name": "Terminate"
},
{
"name": "ToggleOrientation"
},
{
"name": "ToggleStacking"
},
{
"name": "ToggleSticky"
},
{
"name": "ToggleTiling"
},
{
"name": "ToggleWindowFloating"
},
{
"name": "Workspace",
"type": "u8"
}
],
"Dependencies": {
"Direction": [
{
"name": "Left"
},
{
"name": "Right"
},
{
"name": "Up"
},
{
"name": "Down"
}
],
"Orientation": [
{
"name": "Horizontal"
},
{
"name": "Vertical"
}
],
"System": [
{
"name": "AppLibrary"
},
{
"name": "BrightnessDown"
},
{
"name": "BrightnessUp"
},
{
"name": "HomeFolder"
},
{
"name": "KeyboardBrightnessDown"
},
{
"name": "KeyboardBrightnessUp"
},
{
"name": "Launcher"
},
{
"name": "LockScreen"
},
{
"name": "Mute"
},
{
"name": "MuteMic"
},
{
"name": "PlayPause"
},
{
"name": "PlayNext"
},
{
"name": "PlayPrev"
},
{
"name": "Screenshot"
},
{
"name": "Terminal"
},
{
"name": "VolumeLower"
},
{
"name": "VolumeRaise"
},
{
"name": "WebBrowser"
},
{
"name": "WindowSwitcher"
},
{
"name": "WindowSwitcherPrevious"
},
{
"name": "WorkspaceOverview"
}
],
"FocusDirection": [
{
"name": "Left"
},
{
"name": "Right"
},
{
"name": "Up"
},
{
"name": "Down"
},
{
"name": "In"
},
{
"name": "Out"
}
],
"ResizeDirection": [
{
"name": "Inwards"
},
{
"name": "Outwards"
}
]
}
}
20 changes: 20 additions & 0 deletions generators/shortcut-actions/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
fetchurl,
runCommand,
python3,
}:
let
actionRs = fetchurl {
url = "https://github.com/pop-os/cosmic-settings-daemon/blob/61c76a9d060827402eeb9fe92cae73ce159d66e5/config/src/shortcuts/action.rs";
hash = "sha256-Qv2ACmoAm98GD2nhIXJpERSJdGhl/BxumfQH3EJzh+4=";
};
in
runCommand "shortcut-actions" { buildInputs = [ python3 ]; } ''
cp ${actionRs} action.rs
cp ${./main.py} main.py
python3 main.py
mkdir -p $out
cp shortcut-actions.json $out
''
104 changes: 104 additions & 0 deletions generators/shortcut-actions/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import json
import re
from typing import Any, Dict, List, Set


class EnumParser:
def __init__(self, content: str):
self.content = content
self.parsed_enums: Dict[str, List[Dict[str, Any]]] = {}
self.enum_dependencies: Set[str] = set()

def find_enum_definition(self, enum_name: str) -> str:
"""
Find the full definition of an enum in the content.
"""
enum_pattern = rf"pub enum {enum_name} \{{([\s\S]*?)\}}"
enum_match = re.search(enum_pattern, self.content)

return enum_match.group(1) if enum_match else ""

def clean_enum_content(self, content: str) -> str:
"""
Remove comments from enum content.
"""
# Remove multi-line comments
content = re.sub(r"/\*[\s\S]*?\*/", "", content)
# Remove single-line comments
content = re.sub(r"//[^\n]*\n", "\n", content)

return content

def parse_enum_variants(self, enum_name: str) -> List[Dict[str, Any]]:
"""
Parse an enum's variants and detect dependencies.
"""
if enum_name in self.parsed_enums:
return self.parsed_enums[enum_name]

enum_content = self.find_enum_definition(enum_name)
if not enum_content:
return []

enum_content = self.clean_enum_content(enum_content)
variants = []

variant_pattern = r"([A-Za-z]+)(?:\((.*?)\))?,"
matches = re.finditer(variant_pattern, enum_content)

for match in matches:
variant_name = match.group(1)
variant_type = match.group(2)

variant_info = {"name": variant_name}

if variant_type:
variant_info["type"] = variant_type.strip()

# Check if the variant type is another enum
enum_types = re.findall(r"([A-Z][a-zA-Z]+)", variant_type)
for enum_type in enum_types:
if self.find_enum_definition(enum_type):
self.enum_dependencies.add(enum_type)

variants.append(variant_info)

self.parsed_enums[enum_name] = variants
return variants

def parse_all_actions(self) -> Dict[str, Any]:
"""
Parse all actions in the Action enum and all dependent enums recursively.
"""
self.parse_enum_variants("Action")

processed_deps = set()
while self.enum_dependencies - processed_deps:
new_dep = (self.enum_dependencies - processed_deps).pop()
self.parse_enum_variants(new_dep)
processed_deps.add(new_dep)

result = {
"Actions": self.parsed_enums["Action"],
"Dependencies": {
enum_name: self.parsed_enums[enum_name]
for enum_name in self.enum_dependencies
},
}

return result


def main():
with open("action.rs", "r") as file:
content = file.read()

parser = EnumParser(content)
result = parser.parse_all_actions()

with open("shortcut-actions.json", "w") as f:
json.dump(result, f, indent=2)


if __name__ == "__main__":
main()
Loading

0 comments on commit 4ec258d

Please sign in to comment.