Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions sublime_lib/_util/collections.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from __future__ import annotations
from collections.abc import Iterable, Mapping
from typing import Callable, TypeVar
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from sublime_types import Value
from typing import Callable

_V = TypeVar('_V')

__all__ = ['projection', 'get_selector']


def projection(d: Mapping[str, _V], keys: Mapping[str, str] | Iterable[str]) -> Mapping[str, _V]:
def projection(d: Mapping[str, Value], keys: Mapping[str, str] | Iterable[str]) -> Value:
"""
Return a new :class:`Mapping` with keys of ``d`` restricted to values in ``keys``.

Expand Down Expand Up @@ -38,13 +41,16 @@ def projection(d: Mapping[str, _V], keys: Mapping[str, str] | Iterable[str]) ->
}


def get_selector(selector: object, default_value: object = None) -> Callable:
def get_selector(
selector: Callable[[Mapping[str, Value]], Value] | Iterable[str] | str,
default_value: Value = None
) -> Callable[[Mapping[str, Value]], Value]:
if callable(selector):
return selector
elif isinstance(selector, str):
return lambda this: this.get(selector, default_value)
elif isinstance(selector, Iterable):
return lambda this: projection(this, selector) # type: ignore
return lambda this: projection(this, selector)
else:
raise TypeError(
'The selector should be a function, string, or iterable of strings.'
Expand Down
18 changes: 8 additions & 10 deletions sublime_lib/settings_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@

if TYPE_CHECKING:
from collections.abc import Iterable, Mapping
from typing import Any, Callable
from typing_extensions import TypeAlias

Value: TypeAlias = bool | str | int | float | list[Any] | dict[str, Any] | None
from sublime_types import Value
from typing import Callable

_NO_DEFAULT = NamedValue('SettingsDict.NO_DEFAULT')


class SettingsDict():
class SettingsDict:
"""Wraps a :class:`sublime.Settings` object `settings`
with a :class:`dict`-like interface.

Expand All @@ -42,7 +40,7 @@ class SettingsDict():
methods on the :class:`~collections.ChainMap` will raise an error.
"""

NO_DEFAULT = _NO_DEFAULT
NO_DEFAULT: NamedValue = _NO_DEFAULT

def __init__(self, settings: sublime.Settings):
self.settings: sublime.Settings = settings
Expand Down Expand Up @@ -161,7 +159,7 @@ def update(

def subscribe(
self,
selector: Value,
selector: Callable[[Mapping[str, Value]], Value] | Iterable[str] | str,
callback: Callable[[Value, Value], None],
default_value: Value = None
) -> Callable[[], None]:
Expand All @@ -188,13 +186,13 @@ def subscribe(
.. versionchanged:: 1.1
Return an unsubscribe callback.
"""
selector_fn = get_selector(selector)
selector_fn = get_selector(selector, default_value)

saved_value = selector_fn(self)
saved_value = selector_fn(self) # type: ignore

def onchange() -> None:
nonlocal saved_value
new_value = selector_fn(self)
new_value = selector_fn(self) # type: ignore

if new_value != saved_value:
previous_value = saved_value
Expand Down
2 changes: 1 addition & 1 deletion sublime_lib/window_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sublime

if TYPE_CHECKING:
from .settings_dict import Value
from sublime_types import Value

from .view_utils import _temporarily_scratch_unsaved_views

Expand Down
Loading