mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-08-04 01:58:18 +00:00
add initial autocomplete for installed templatetags (#46)
This commit is contained in:
parent
5eb8a775e4
commit
c16635b1c0
8 changed files with 359 additions and 58 deletions
8
crates/djls-project/Cargo.toml
Normal file
8
crates/djls-project/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "djls-project"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
pyo3 = { workspace = true }
|
||||
tower-lsp = { workspace = true }
|
62
crates/djls-project/src/lib.rs
Normal file
62
crates/djls-project/src/lib.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
mod templatetags;
|
||||
|
||||
pub use templatetags::TemplateTags;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DjangoProject {
|
||||
path: PathBuf,
|
||||
template_tags: Option<TemplateTags>,
|
||||
}
|
||||
|
||||
impl DjangoProject {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
Self {
|
||||
path,
|
||||
template_tags: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_initialize_params(params: &InitializeParams) -> Option<Self> {
|
||||
// Try current directory first
|
||||
let path = std::env::current_dir()
|
||||
.ok()
|
||||
// Fall back to workspace root if provided
|
||||
.or_else(|| {
|
||||
params
|
||||
.root_uri
|
||||
.as_ref()
|
||||
.and_then(|uri| uri.to_file_path().ok())
|
||||
});
|
||||
|
||||
path.map(Self::new)
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self) -> PyResult<()> {
|
||||
Python::with_gil(|py| {
|
||||
// Add project to Python path
|
||||
let sys = py.import("sys")?;
|
||||
let py_path = sys.getattr("path")?;
|
||||
py_path.call_method1("append", (self.path.to_str().unwrap(),))?;
|
||||
|
||||
// Setup Django
|
||||
let django = py.import("django")?;
|
||||
django.call_method0("setup")?;
|
||||
|
||||
self.template_tags = Some(TemplateTags::from_python(py)?);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn template_tags(&self) -> Option<&TemplateTags> {
|
||||
self.template_tags.as_ref()
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
94
crates/djls-project/src/templatetags.rs
Normal file
94
crates/djls-project/src/templatetags.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyList};
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TemplateTags(Vec<TemplateTag>);
|
||||
|
||||
impl Deref for TemplateTags {
|
||||
type Target = Vec<TemplateTag>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateTags {
|
||||
fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
fn process_library(
|
||||
module_name: &str,
|
||||
library: &Bound<'_, PyAny>,
|
||||
tags: &mut Vec<TemplateTag>,
|
||||
) -> PyResult<()> {
|
||||
let tags_dict = library.getattr("tags")?;
|
||||
let dict = tags_dict.downcast::<PyDict>()?;
|
||||
|
||||
for (key, value) in dict.iter() {
|
||||
let tag_name = key.extract::<String>()?;
|
||||
let doc = value.getattr("__doc__")?.extract().ok();
|
||||
|
||||
let library_name = if module_name.is_empty() {
|
||||
"builtins".to_string()
|
||||
} else {
|
||||
module_name.split('.').last().unwrap_or("").to_string()
|
||||
};
|
||||
|
||||
tags.push(TemplateTag::new(tag_name, library_name, doc));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn from_python(py: Python) -> PyResult<TemplateTags> {
|
||||
let mut template_tags = TemplateTags::new();
|
||||
|
||||
let engine = py
|
||||
.import("django.template.engine")?
|
||||
.getattr("Engine")?
|
||||
.call_method0("get_default")?;
|
||||
|
||||
// Built-in template tags
|
||||
let builtins_attr = engine.getattr("template_builtins")?;
|
||||
let builtins = builtins_attr.downcast::<PyList>()?;
|
||||
for builtin in builtins {
|
||||
Self::process_library("", &builtin, &mut template_tags.0)?;
|
||||
}
|
||||
|
||||
// Custom template libraries
|
||||
let libraries_attr = engine.getattr("template_libraries")?;
|
||||
let libraries = libraries_attr.downcast::<PyDict>()?;
|
||||
for (module_name, library) in libraries.iter() {
|
||||
let module_name = module_name.extract::<String>()?;
|
||||
Self::process_library(&module_name, &library, &mut template_tags.0)?;
|
||||
}
|
||||
|
||||
Ok(template_tags)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TemplateTag {
|
||||
name: String,
|
||||
library: String,
|
||||
doc: Option<String>,
|
||||
}
|
||||
|
||||
impl TemplateTag {
|
||||
fn new(name: String, library: String, doc: Option<String>) -> Self {
|
||||
Self { name, library, doc }
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn library(&self) -> &String {
|
||||
&self.library
|
||||
}
|
||||
|
||||
pub fn doc(&self) -> &Option<String> {
|
||||
&self.doc
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue