-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Akuli <[email protected]> Co-authored-by: rdbende <[email protected]>
- Loading branch information
1 parent
9b32234
commit 9ff4be0
Showing
6 changed files
with
278 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
from functools import partial | ||
from pathlib import Path | ||
from typing import Callable, Union | ||
|
||
from porcupine.tabs import FileTab | ||
|
||
|
||
@dataclass(frozen=True) | ||
class BareAction: | ||
"""Action that requires no context in the callback""" | ||
|
||
name: str | ||
description: str | ||
callback: Callable[[], None] | ||
availability_callback: Callable[[], bool] | ||
|
||
|
||
@dataclass(frozen=True) | ||
class FileTabAction: | ||
"""Action that requires a FileTab to be provided to the callback""" | ||
|
||
name: str | ||
description: str | ||
callback: Callable[[FileTab], None] | ||
availability_callback: Callable[[FileTab], bool] | ||
|
||
|
||
@dataclass(frozen=True) | ||
class PathAction: | ||
"""Action that requires a Path to be provided to the callback""" | ||
|
||
name: str | ||
description: str | ||
callback: Callable[[Path], None] | ||
availability_callback: Callable[[Path], bool] | ||
|
||
|
||
Action = Union[BareAction, FileTabAction, PathAction] | ||
|
||
_actions: dict[str, Action] = {} | ||
|
||
|
||
def register_bare_action( | ||
*, | ||
name: str, | ||
description: str, | ||
callback: Callable[..., None], | ||
availability_callback: Callable[[], bool] = lambda: True, | ||
) -> BareAction: | ||
if name in _actions: | ||
raise ValueError(f"Action with the name {name!r} already exists") | ||
action = BareAction( | ||
name=name, | ||
description=description, | ||
callback=callback, | ||
availability_callback=availability_callback, | ||
) | ||
_actions[name] = action | ||
return action | ||
|
||
|
||
def register_filetab_action( | ||
*, | ||
name: str, | ||
description: str, | ||
callback: Callable[[FileTab], None], | ||
availability_callback: Callable[[FileTab], bool] = lambda tab: True, | ||
) -> FileTabAction: | ||
if name in _actions: | ||
raise ValueError(f"Action with the name {name!r} already exists") | ||
action = FileTabAction( | ||
name=name, | ||
description=description, | ||
callback=callback, | ||
availability_callback=availability_callback, | ||
) | ||
_actions[name] = action | ||
return action | ||
|
||
|
||
def register_path_action( | ||
*, | ||
name: str, | ||
description: str, | ||
callback: Callable[[Path], None], | ||
availability_callback: Callable[[Path], bool] = lambda path: True, | ||
) -> PathAction: | ||
if name in _actions: | ||
raise ValueError(f"Action with the name {name!r} already exists") | ||
action = PathAction( | ||
name=name, | ||
description=description, | ||
callback=callback, | ||
availability_callback=availability_callback, | ||
) | ||
_actions[name] = action | ||
return action | ||
|
||
|
||
def get_action(name: str) -> Action | None: | ||
return _actions.get(name) | ||
|
||
|
||
def get_all_actions() -> dict[str, Action]: | ||
return _actions.copy() | ||
|
||
|
||
# Availability Helpers | ||
|
||
|
||
def filetype_is(filetypes: str | list[str]) -> Callable[[FileTab], bool]: | ||
def _filetype_is(filetypes: list[str], tab: FileTab) -> bool: | ||
try: | ||
filetype = tab.settings.get("filetype_name", object) | ||
except KeyError: | ||
# don't ask me why a `get` method can raise a KeyError :p | ||
return False | ||
|
||
return filetype in filetypes | ||
|
||
if isinstance(filetypes, str): | ||
filetypes = [filetypes] | ||
|
||
return partial(_filetype_is, filetypes) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from porcupine import actions | ||
|
||
|
||
def test_action_registry(): | ||
bare_action = actions.register_bare_action( | ||
name="bare action", description="", callback=lambda: None | ||
) | ||
filetab_action = actions.register_filetab_action( | ||
name="filetab action", description="", callback=lambda tab: None | ||
) | ||
path_action = actions.register_path_action( | ||
name="path action", description="", callback=lambda path: None | ||
) | ||
|
||
assert isinstance(bare_action, actions.BareAction) | ||
assert isinstance(filetab_action, actions.FileTabAction) | ||
assert isinstance(path_action, actions.PathAction) | ||
|
||
all_actions = actions.get_all_actions() | ||
for action in [bare_action, filetab_action, path_action]: | ||
assert actions.get_action(action.name) is action | ||
assert action in all_actions.values() | ||
|
||
assert actions.get_action("nonexistent action") is None | ||
|
||
all_actions["garbage"] = "mean lean fighting machine" # type: ignore | ||
assert ( | ||
actions.get_action("garbage") is None | ||
), "`all_actions` should be a copy, changes to it should not effect `_actions`" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters