Skip to content

Commit

Permalink
feat: add decorators for event handler registration
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Cherng <jfcherng@gmail.com>
  • Loading branch information
jfcherng committed Nov 18, 2020
1 parent 98f3d67 commit 1d1179e
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 2 deletions.
4 changes: 4 additions & 0 deletions st3/lsp_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from ._client_handler import ClientHandler
from ._client_handler import as_notification_handler, as_request_handler
from .api_wrapper_interface import ApiWrapperInterface
from .generic_client_handler import GenericClientHandler
from .npm_client_handler import NpmClientHandler
Expand All @@ -14,4 +15,7 @@
'ServerResourceInterface',
'ServerStatus'
'ServerNpmResource',
# decorator-related
'as_notification_handler',
'as_request_handler',
]
6 changes: 6 additions & 0 deletions st3/lsp_utils/_client_handler/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from .decorator import HANDLER_MARKS
from .decorator import as_notification_handler, as_request_handler
from LSP.plugin import __version__ as lsp_version


Expand All @@ -8,4 +10,8 @@

__all__ = [
'ClientHandler',
# decorator-related
'HANDLER_MARKS',
'as_notification_handler',
'as_request_handler',
]
39 changes: 39 additions & 0 deletions st3/lsp_utils/_client_handler/decorator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from LSP.plugin.core.typing import Any, Callable, Iterable, Union

__all__ = [
"as_notification_handler",
"as_request_handler",
]

# the first argument is always "self"
T_HANDLER = Callable[[Any, Any], None]
T_SERVER_EVENTS = Union[str, Iterable[str]]

HANDLER_MARKS = {
"notification": "__handle_notification_events",
"request": "__handle_request_events",
}


def as_notification_handler(server_events: T_SERVER_EVENTS) -> Callable[[T_HANDLER], T_HANDLER]:
""" Marks the decorated function as a "notification" event handler. """

return _as_handler("notification", server_events)


def as_request_handler(server_events: T_SERVER_EVENTS) -> Callable[[T_HANDLER], T_HANDLER]:
""" Marks the decorated function as a "request" event handler. """

return _as_handler("request", server_events)


def _as_handler(client_event: str, server_events: T_SERVER_EVENTS) -> Callable[[T_HANDLER], T_HANDLER]:
""" Marks the decorated function as a event handler. """

server_events = [server_events] if isinstance(server_events, str) else list(server_events)

def decorator(func: T_HANDLER) -> T_HANDLER:
setattr(func, HANDLER_MARKS[client_event], server_events)
return func

return decorator
26 changes: 24 additions & 2 deletions st3/lsp_utils/generic_client_handler.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from ._client_handler import ClientHandler
from ._client_handler import ClientHandler, HANDLER_MARKS
from .api_wrapper_interface import ApiWrapperInterface
from .server_resource_interface import ServerResourceInterface
from abc import ABCMeta
from LSP.plugin import ClientConfig
from LSP.plugin import WorkspaceFolder
from LSP.plugin.core.typing import Dict, List, Optional, Tuple
import inspect
import os
import shutil
import sublime
Expand Down Expand Up @@ -187,4 +188,25 @@ def on_ready(self, api: ApiWrapperInterface) -> None:
:param api: The API instance for interacting with the server.
"""
pass
self._register_custom_server_event_handlers(api)

def _register_custom_server_event_handlers(self, api: ApiWrapperInterface) -> None:
"""
Register decorator-style custom event handlers.
This method works as following steps:
1. Scan through all methods of this object.
2. If a method is decorated, it will has a "handler mark" attribute which is put by the decorator.
3. Register the method with wanted events, which are stored in the "handler mark" attribute.
:param api: The API instance for interacting with the server.
"""
for _, func in inspect.getmembers(self, predicate=inspect.isroutine):
# client_event is like "notification", "request"
for client_event, handler_mark in HANDLER_MARKS.items():
event_registrator = getattr(api, "on_" + client_event, None)
if callable(event_registrator):
server_events = getattr(func, handler_mark, []) # type: List[str]
for server_event in server_events:
event_registrator(server_event, func)

0 comments on commit 1d1179e

Please sign in to comment.