Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Cherng <[email protected]>
  • Loading branch information
jfcherng committed May 19, 2024
1 parent 65c45f2 commit 52e59b2
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 55 deletions.
3 changes: 3 additions & 0 deletions boot.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from __future__ import annotations


def reload_plugin() -> None:
import sys

Expand Down
11 changes: 11 additions & 0 deletions dependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"*": {
"*": [
"annotated-types",
"more-itertools",
"pydantic",
"pydantic-core",
"typing-extensions"
]
}
}
72 changes: 25 additions & 47 deletions plugin/completion.py
Original file line number Diff line number Diff line change
@@ -1,77 +1,55 @@
from __future__ import annotations

import json
from functools import lru_cache
from itertools import groupby
from typing import Generator, Iterable

import sublime

from .constant import DB_DIR
from .types import DatabaseItem, DbSchema, NormalizedDatabaseItem
from .data_types import DbItem, DbModel, NormalizedDbItem


@lru_cache
def load_database(version: str) -> DbSchema:
return json.loads(sublime.load_resource(str(DB_DIR / f"{version}.json")))
def load_db(version: str) -> DbModel:
return DbModel.model_validate_json(sublime.load_resource(str(DB_DIR / f"{version}.json")))


@lru_cache
def get_completion_list(version_str: str) -> sublime.CompletionList:
"""
Gets the completion items.
:param version_str: Versions separated with ","
:type version_str: str
:returns: The completion items.
:rtype: sublime.CompletionList
"""

versions = sorted(set(filter(None, map(str.strip, version_str.split(",")))))
items = _get_database_items(versions)
def get_completion_list(versions: tuple[str, ...]) -> sublime.CompletionList:
"""Gets the completion items."""
db_items = [item for version in versions for item in _list_db_items(version)]

return sublime.CompletionList(
tuple(
map(
lambda item: sublime.CompletionItem(
trigger=item.item_name,
annotation=f"{item.lib_name} {'/'.join(item.lib_versions)}",
completion=item.item_name,
completion_format=sublime.COMPLETION_FORMAT_TEXT,
kind=(sublime.KIND_ID_MARKUP, "c", ""),
details="",
),
_normalize_database_items(items),
sublime.CompletionItem(
trigger=item.item_name,
annotation=f"{item.lib_name} {'/'.join(item.lib_versions)}",
completion=item.item_name,
completion_format=sublime.COMPLETION_FORMAT_TEXT,
kind=(sublime.KIND_ID_MARKUP, "c", ""),
details="",
)
for item in _normalize_db_items_for_completion(db_items)
)
)


def _get_database_items(versions: Iterable[str]) -> Generator[DatabaseItem, None, None]:
for version in versions:
db = load_database(version)
for name in db["classes"]:
yield DatabaseItem(
lib_name=db["name"],
lib_version=db["version"],
item_name=name,
)
def _list_db_items(version: str) -> Generator[DbItem, None, None]:
db = load_db(version)
yield from (DbItem(lib_name=db.name, lib_version=db.version, item_name=name) for name in db.classes)


def _normalize_database_items(items: Iterable[DatabaseItem]) -> Generator[NormalizedDatabaseItem, None, None]:
def sorter(item: DatabaseItem) -> tuple[str, str]:
def _normalize_db_items_for_completion(db_items: Iterable[DbItem]) -> Generator[NormalizedDbItem, None, None]:
def sorter(item: DbItem) -> tuple[str, str]:
return (item.lib_name, item.item_name)

# pre-sort for groupby
items = sorted(items, key=sorter)

db_items = sorted(db_items, key=sorter)
# merges same-name items which have different versions
for _, group in groupby(items, sorter):
group_items = tuple(group)
group_item = group_items[0]
yield NormalizedDatabaseItem(
lib_name=group_item.lib_name,
lib_versions=sorted(item.lib_version for item in group_items),
item_name=group_item.item_name,
for (lib_name, item_name), group in groupby(db_items, sorter):
yield NormalizedDbItem(
lib_name=lib_name,
lib_versions=sorted(item.lib_version for item in group),
item_name=item_name,
)
11 changes: 4 additions & 7 deletions plugin/types.py → plugin/data_types.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import TypedDict
from pydantic import BaseModel


class DbSchema(TypedDict):
class DbModel(BaseModel):
name: str
version: str
classes: list[str]


@dataclass
class DatabaseItem:
class DbItem(BaseModel):
lib_name: str
"""The name of the lib."""
lib_version: str
Expand All @@ -20,8 +18,7 @@ class DatabaseItem:
"""The trigger of the completion."""


@dataclass
class NormalizedDatabaseItem:
class NormalizedDbItem(BaseModel):
lib_name: str
"""The name of the lib."""
lib_versions: list[str]
Expand Down
11 changes: 10 additions & 1 deletion plugin/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import sublime
import sublime_plugin

from plugin.utils import sort_uniq

from .completion import get_completion_list
from .settings import get_merged_plugin_setting

Expand All @@ -25,8 +27,15 @@ def on_query_completions(
if not self._point_match_selectors(view, point, selectors):
return None

return get_completion_list(",".join(get_merged_plugin_setting(window, "versions")))
return get_completion_list(_get_versions(window))

@staticmethod
def _point_match_selectors(view: sublime.View, point: int, selectors: Iterable[str]) -> bool:
return any(view.match_selector(point, selector) for selector in selectors)


def _get_versions(window: sublime.Window) -> tuple[str, ...]:
versions = get_merged_plugin_setting(window, "versions")
if isinstance(versions, str):
versions = (versions,)
return tuple(sort_uniq(versions))
20 changes: 20 additions & 0 deletions plugin/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

from itertools import groupby
from operator import itemgetter
from typing import Any, Callable, Generator, Iterable, TypeVar

_T = TypeVar("_T")


def sort_uniq(
seq: Iterable[_T],
*,
key: Callable[[_T], Any] | None = None,
reverse: bool = False,
) -> Generator[_T, None, None]:
key = key or (lambda x: x)
yield from map(
itemgetter(0),
groupby(sorted(seq, key=key, reverse=reverse), key=key), # type: ignore
)
8 changes: 8 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements-dev.in -o requirements-dev.txt
annotated-types==0.6.0
# via pydantic
click==8.1.7
# via typer
colorama==0.4.6
Expand All @@ -12,6 +14,10 @@ mypy==1.10.0
# via -r requirements-dev.in
mypy-extensions==1.0.0
# via mypy
pydantic==2.7.1
# via -r requirements.in
pydantic-core==2.18.2
# via pydantic
pygments==2.18.0
# via rich
rich==13.7.1
Expand All @@ -28,6 +34,8 @@ typing-extensions==4.11.0
# via
# -r requirements-dev.in
# mypy
# pydantic
# pydantic-core
# typer
webencodings==0.5.1
# via tinycss2
1 change: 1 addition & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pydantic>=2.7,<3
10 changes: 10 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements.in -o requirements.txt
annotated-types==0.6.0
# via pydantic
pydantic==2.7.1
# via -r requirements.in
pydantic-core==2.18.2
# via pydantic
typing-extensions==4.11.0
# via
# pydantic
# pydantic-core

0 comments on commit 52e59b2

Please sign in to comment.