Skip to content

Commit

Permalink
Merge pull request #48 from fourdigits/add-goto-for-libs
Browse files Browse the repository at this point in the history
Add goto support for tags and filters
  • Loading branch information
rubenhesselink authored Aug 28, 2024
2 parents 80ac161 + a451f8c commit 7a85fcf
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 12 deletions.
4 changes: 4 additions & 0 deletions djlsp/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Template:
class Tag:
name: str = ""
docs: str = ""
source: str = ""
inner_tags: list[str] = ""
closing_tag: str = ""

Expand All @@ -22,6 +23,7 @@ class Tag:
class Filter:
name: str = ""
docs: str = ""
source: str = ""


@dataclass
Expand Down Expand Up @@ -56,13 +58,15 @@ def update(self, django_data: dict):
name: Filter(
name=name,
docs=filter_options.get("docs", ""),
source=filter_options.get("source", ""),
)
for name, filter_options in lib_data.get("filters", {}).items()
},
tags={
tag: Tag(
name=tag,
docs=tag_options.get("docs"),
source=tag_options.get("source", ""),
inner_tags=tag_options.get("inner_tags", []),
closing_tag=tag_options.get("closing_tag"),
)
Expand Down
45 changes: 33 additions & 12 deletions djlsp/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ def goto_definition(self, line, character):
re.compile(r""".*{% ?(extends|include) ('|")([\w\-\./]*)$"""),
self.get_template_definition,
),
(re.compile(r"^.*{% ?(\w*)$"), self.get_tag_definition),
(re.compile(r"^.*({%|{{).*?\|(\w*)$"), self.get_filter_definition),
(
re.compile(r".*({{|{% \w+ ).*?([\w\d_\.]*)$"),
self.get_context_definition,
Expand All @@ -370,24 +372,43 @@ def goto_definition(self, line, character):
return definition(line, character, match)
return None

def create_location(self, location, path, line):
root_path = (
self.workspace_index.src_path
if location == "src"
else self.workspace_index.env_path
)
return Location(
uri=f"file://{root_path}/{path}",
range=Range(
start=Position(line=int(line), character=0),
end=Position(line=int(line), character=0),
),
)

def get_template_definition(self, line, character, match: Match):
if match_after := re.match(r'^(.*)".*', self.document.lines[line][character:]):
template_name = match.group(3) + match_after.group(1)
logger.debug(f"Find template goto definition for: {template_name}")
if template := self.workspace_index.templates.get(template_name):
location, path = template.path.split(":")
root_path = (
self.workspace_index.src_path
if location == "src"
else self.workspace_index.env_path
)
return Location(
uri=f"file://{root_path}/{path}",
range=Range(
start=Position(line=0, character=0),
end=Position(line=0, character=0),
),
)
return self.create_location(location, path, 0)

def get_tag_definition(self, line, character, match: Match):
full_match = self._get_full_definition_name(line, character, match.group(1))
logger.debug(f"Find tag goto definition for: {full_match}")
for lib in self.loaded_libraries:
if tag := self.workspace_index.libraries[lib].tags.get(full_match):
if tag.source:
return self.create_location(*tag.source.split(":"))

def get_filter_definition(self, line, character, match: Match):
full_match = self._get_full_definition_name(line, character, match.group(2))
logger.debug(f"Find filter goto definition for: {full_match}")
for lib in self.loaded_libraries:
if filter_ := self.workspace_index.libraries[lib].filters.get(full_match):
if filter_.source:
return self.create_location(*filter_.source.split(":"))

def get_context_definition(self, line, character, match: Match):
first_match = match.group(2)
Expand Down
25 changes: 25 additions & 0 deletions djlsp/scripts/django-collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,29 @@ def to_json(self):
indent=4,
)

def get_source_from_type(self, type_):
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func

type_ = unwrap(type_)

try:
source_file = inspect.getsourcefile(type_)
line = inspect.getsourcelines(type_)[1]
except Exception as e:
logger.error(e)
return ""

if source_file.startswith(self.project_src_path):
path = source_file.removeprefix(self.project_src_path).lstrip("/")
return f"src:{path}:{line}"
elif source_file.startswith(sys.prefix):
path = source_file.removeprefix(sys.prefix).lstrip("/")
return f"env:{path}:{line}"
return ""

# File watcher globs
# ---------------------------------------------------------------------------------
def get_file_watcher_globs(self):
Expand Down Expand Up @@ -336,12 +359,14 @@ def _parse_library(self, lib) -> dict:
"tags": {
name: {
"docs": func.__doc__.strip() if func.__doc__ else "",
"source": self.get_source_from_type(func),
}
for name, func in lib.tags.items()
},
"filters": {
name: {
"docs": func.__doc__.strip() if func.__doc__ else "",
"source": self.get_source_from_type(func),
}
for name, func in lib.filters.items()
},
Expand Down

0 comments on commit 7a85fcf

Please sign in to comment.