Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic workspace index dataclasses #9

Merged
merged 5 commits into from
Jun 13, 2024
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
117 changes: 51 additions & 66 deletions djlsp/constants.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,37 @@
BUILTIN = "__builtins__"

FALLBACK_DJANGO_DATA = {
"file_watcher_globs": [
"**/templates/**",
"**/templatetags/**",
"**/static/**",
],
"file_watcher_globs": ["**/templates/**", "**/templatetags/**", "**/static/**"],
"static_files": [],
"urls": [],
"templates": [],
"libraries": {
"__builtins__": {
"tags": [
"autoescape",
"comment",
"cycle",
"csrf_token",
"debug",
"filter",
"firstof",
"for",
"if",
"ifchanged",
"load",
"lorem",
"now",
"regroup",
"resetcycle",
"spaceless",
"templatetag",
"url",
"verbatim",
"widthratio",
"with",
"block",
"extends",
"include",
"endautoescape",
"endfilter",
"empty",
"endfor",
"else",
"elif",
"endifendifchanged",
"endspaceless",
"endverbatim",
"endwith",
"endblock",
],
"tags": {
"autoescape": {"inner_tags": [], "closing_tag": "endautoescape"},
"comment": {"inner_tags": [], "closing_tag": "endcomment"},
"cycle": {},
"csrf_token": {},
"debug": {},
"filter": {"inner_tags": [], "closing_tag": "endfilter"},
"firstof": {},
"for": {"inner_tags": ["empty"], "closing_tag": "endfor"},
"if": {"inner_tags": ["else", "elif"], "closing_tag": "endif"},
"ifchanged": {"inner_tags": [], "closing_tag": "endifchanged"},
"load": {},
"lorem": {},
"now": {},
"regroup": {},
"resetcycle": {},
"spaceless": {"inner_tags": [], "closing_tag": "endspaceless"},
"templatetag": {},
"url": {},
"verbatim": {"inner_tags": [], "closing_tag": "endverbatim"},
"widthratio": {},
"with": {"inner_tags": [], "closing_tag": "endwith"},
"block": {"inner_tags": [], "closing_tag": "endblock"},
"extends": {},
"include": {},
},
"filters": [
"addslashes",
"capfirst",
Expand Down Expand Up @@ -108,21 +92,23 @@
"pprint",
],
},
"cache": {"tags": ["cache", "endcache"], "filters": []},
"cache": {
"tags": {"cache": {"inner_tags": [], "closing_tag": "endcache"}},
"filters": [],
},
"i18n": {
"tags": [
"get_available_languages",
"get_language_info",
"get_language_info_list",
"get_current_language",
"get_current_language_bidi",
"trans",
"translate",
"blocktrans",
"blocktranslate",
"language",
"endlanguage",
],
"tags": {
"get_available_languages": {},
"get_language_info": {},
"get_language_info_list": {},
"get_current_language": {},
"get_current_language_bidi": {},
"trans": {},
"translate": {},
"blocktrans": {},
"blocktranslate": {},
"language": {"inner_tags": [], "closing_tag": "endlanguage"},
},
"filters": [
"language_name",
"language_name_translated",
Expand All @@ -131,22 +117,21 @@
],
},
"l10n": {
"tags": ["localize", "endlocalize"],
"tags": {"localize": {"inner_tags": [], "closing_tag": "endlocalize"}},
"filters": ["localize", "unlocalize"],
},
"static": {
"tags": ["get_static_prefix", "get_media_prefix", "static"],
"tags": {"get_static_prefix": {}, "get_media_prefix": {}, "static": {}},
"filters": [],
},
"tz": {
"tags": [
"localtime",
"timezoninitializationOptionse",
"get_current_timezone",
"endlocaltime",
"endtimezone",
],
"tags": {
"localtime": {"inner_tags": [], "closing_tag": "endlocaltime"},
"timezone": {"inner_tags": [], "closing_tag": "endtimezone"},
"get_current_timezone": {},
},
"filters": ["localtime", "utc", "timezone"],
},
},
"templates": {},
}
60 changes: 60 additions & 0 deletions djlsp/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from dataclasses import dataclass, field


@dataclass
class Template:
name: str = ""
extends: str | None = None
blocks: list[str] | None = None
context: dict = field(default_factory=dict)


@dataclass
class Tag:
name: str = ""
inner_tags: list[str] = ""
closing_tag: str = ""


@dataclass
class Library:
name: str = ""
tags: dict[str, Tag] = field(default_factory=dict)
filters: list[str] = field(default_factory=list)


@dataclass
class WorkspaceIndex:
file_watcher_globs: [str] = field(default_factory=list)
static_files: [str] = field(default_factory=list)
urls: [str] = field(default_factory=list)
libraries: dict[str, Library] = field(default_factory=dict)
templates: dict[str, Template] = field(default_factory=dict)

def update(self, django_data: dict):
self.file_watcher_globs = django_data.get(
"file_watcher_globs", self.file_watcher_globs
)
self.static_files = django_data.get("static_files", self.static_files)
self.urls = django_data.get("urls", self.urls)

self.libraries = {
lib_name: Library(
name=lib_name,
filters=lib_data.get("filters", []),
tags={
tag: Tag(
name=tag,
inner_tags=tag_options.get("inner_tags", []),
closing_tag=tag_options.get("closing_tag"),
)
for tag, tag_options in lib_data.get("tags", {}).items()
},
)
for lib_name, lib_data in django_data.get("libraries", {}).items()
}

self.templates = {
name: Template(name=name, **options)
for name, options in django_data.get("templates", {}).items()
}
33 changes: 19 additions & 14 deletions djlsp/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pygls.workspace import TextDocument

from djlsp.constants import BUILTIN
from djlsp.index import WorkspaceIndex

logger = logging.getLogger(__name__)

Expand All @@ -19,8 +20,8 @@ class TemplateParser:
re_filter = re.compile(r"^.*({%|{{) ?[\w \.\|]*\|(\w*)$")
re_template = re.compile(r""".*{% ?(extends|include) ('|")([\w\-:]*)$""")

def __init__(self, django_data: dict, document: TextDocument):
self.django_data = django_data
def __init__(self, workspace_index: WorkspaceIndex, document: TextDocument):
self.workspace_index: WorkspaceIndex = workspace_index
self.document: TextDocument = document

@cached_property
Expand All @@ -32,7 +33,7 @@ def loaded_libraries(self):
[
lib
for lib in match.group(1).strip().split(" ")
if lib in self.django_data["libraries"]
if lib in self.workspace_index.libraries
]
)
logger.debug(f"Loaded libraries: {loaded}")
Expand Down Expand Up @@ -62,7 +63,7 @@ def get_load_completions(self, match: Match):
return sorted(
[
lib
for lib in self.django_data["libraries"].keys()
for lib in self.workspace_index.libraries.keys()
if lib != BUILTIN and lib.startswith(prefix)
]
)
Expand All @@ -73,7 +74,7 @@ def get_static_completions(self, match: Match):
return sorted(
[
static_file
for static_file in self.django_data["static_files"]
for static_file in self.workspace_index.static_files
if static_file.startswith(prefix)
]
)
Expand All @@ -82,17 +83,16 @@ def get_url_completions(self, match: Match):
prefix = match.group(2)
logger.debug(f"Find url matches for: {prefix}")
return sorted(
[url for url in self.django_data["urls"] if url.startswith(prefix)]
[url for url in self.workspace_index.urls if url.startswith(prefix)]
)

def get_template_completions(self, match: Match):
prefix = match.group(3)
logger.debug(f"Find {match.group(1)} matches for: {prefix}")
logger.debug(self.django_data["templates"])
return sorted(
[
template
for template in self.django_data["templates"]
for template in self.workspace_index.templates
if template.startswith(prefix)
]
)
Expand All @@ -102,19 +102,24 @@ def get_tag_completions(self, match: Match):
logger.debug(f"Find tag matches for: {prefix}")

tags = []
for name, lib in self.django_data["libraries"].items():
if name in self.loaded_libraries:
tags.extend(lib["tags"])
for lib_name in self.loaded_libraries:
if lib := self.workspace_index.libraries.get(lib_name):
for tag in lib.tags.values():
tags.append(tag.name)
# TODO: Only add inner/clossing if there is opening tag
tags.extend(tag.inner_tags)
if tag.closing_tag:
tags.append(tag.closing_tag)

return sorted([tag for tag in tags if tag.startswith(prefix)])

def get_filter_completions(self, match: Match):
prefix = match.group(2)
logger.debug(f"Find filter matches for: {prefix}")
filters = []
for name, lib in self.django_data["libraries"].items():
if name in self.loaded_libraries:
filters.extend(lib["filters"])
for lib_name in self.loaded_libraries:
if lib := self.workspace_index.libraries.get(lib_name):
filters.extend(lib.filters)
return sorted(
[filter_name for filter_name in filters if filter_name.startswith(prefix)]
)
Loading