Skip to content

Commit 5a40514

Browse files
wip
1 parent 407ac23 commit 5a40514

File tree

10 files changed

+327
-360
lines changed

10 files changed

+327
-360
lines changed

crates/djls-ide/src/navigation.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use djls_semantic::resolve_template;
22
use djls_semantic::ResolveResult;
33
use djls_source::File;
4-
use djls_source::LineCol;
54
use djls_source::Offset;
6-
use djls_source::PositionEncoding;
75
use djls_templates::parse_template;
86
use djls_templates::Node;
97
use tower_lsp_server::lsp_types;
@@ -12,17 +10,10 @@ use tower_lsp_server::UriExt;
1210
pub fn goto_template_definition(
1311
db: &dyn djls_semantic::Db,
1412
file: File,
15-
position: lsp_types::Position,
16-
encoding: PositionEncoding,
13+
offset: Offset,
1714
) -> Option<lsp_types::GotoDefinitionResponse> {
1815
let nodelist = parse_template(db, file)?;
1916

20-
let line_index = file.line_index(db);
21-
let source = file.source(db);
22-
let line_col = LineCol::new(position.line, position.character);
23-
24-
let offset = encoding.line_col_to_offset(line_index, line_col, source.as_str())?;
25-
2617
let template_name = find_template_name_at_offset(nodelist.nodelist(db), offset)?;
2718
tracing::debug!("Found template reference: '{}'", template_name);
2819

@@ -49,14 +40,9 @@ pub fn goto_template_definition(
4940
pub fn find_template_references(
5041
db: &dyn djls_semantic::Db,
5142
file: File,
52-
position: lsp_types::Position,
53-
encoding: PositionEncoding,
43+
offset: Offset,
5444
) -> Option<Vec<lsp_types::Location>> {
5545
let nodelist = parse_template(db, file)?;
56-
let line_index = file.line_index(db);
57-
let source = file.source(db);
58-
let line_col = LineCol::new(position.line, position.character);
59-
let offset = encoding.line_col_to_offset(line_index, line_col, source.as_str())?;
6046

6147
let template_name = find_template_name_at_offset(nodelist.nodelist(db), offset)?;
6248
tracing::debug!(

crates/djls-ide/src/references.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use djls_semantic::Db as SemanticDb;
2+
use djls_source::File;
3+
use djls_source::LineCol;
4+
use djls_source::Offset;
5+
use djls_source::PositionEncoding;
6+
use djls_templates::parse_template;
7+
use djls_templates::Node;
8+
use tower_lsp_server::lsp_types;
9+
use tower_lsp_server::UriExt;
10+
11+
pub fn references(
12+
db: &dyn SemanticDb,
13+
file: File,
14+
offset: Offset,
15+
) -> Option<Vec<lsp_types::Location>> {
16+
let nodelist = parse_template(db, file)?;
17+
let line_index = file.line_index(db);
18+
let source = file.source(db);
19+
let line_col = LineCol::new(position.line, position.character);
20+
let offset = encoding.line_col_to_offset(line_index, line_col, source.as_str())?;
21+
22+
let template_name = find_template_name_at_offset(nodelist.nodelist(db), offset)?;
23+
tracing::debug!(
24+
"Cursor is inside extends/include tag referencing: '{}'",
25+
template_name
26+
);
27+
28+
let references = djls_semantic::find_references_to_template(db, &template_name);
29+
30+
let locations: Vec<lsp_types::Location> = references
31+
.iter()
32+
.filter_map(|reference| {
33+
let source_template = reference.source(db);
34+
let source_path = source_template.path_buf(db);
35+
let uri = lsp_types::Uri::from_file_path(source_path.as_std_path())?;
36+
37+
let ref_file = djls_source::File::new(db, source_path.clone(), 0);
38+
let line_index = ref_file.line_index(db);
39+
40+
let tag = reference.tag(db);
41+
let tag_span = tag.span(db);
42+
let start_offset = tag_span.start_offset();
43+
let end_offset = tag_span.end_offset();
44+
45+
let start_lc = line_index.to_line_col(start_offset);
46+
let end_lc = line_index.to_line_col(end_offset);
47+
48+
let start_pos = lsp_types::Position {
49+
line: start_lc.line(),
50+
character: start_lc.column(),
51+
};
52+
let end_pos = lsp_types::Position {
53+
line: end_lc.line(),
54+
character: end_lc.column(),
55+
};
56+
57+
Some(lsp_types::Location {
58+
uri,
59+
range: lsp_types::Range {
60+
start: start_pos,
61+
end: end_pos,
62+
},
63+
})
64+
})
65+
.collect();
66+
67+
if locations.is_empty() {
68+
None
69+
} else {
70+
Some(locations)
71+
}
72+
}
73+
74+
fn find_template_name_at_offset(nodes: &[Node], offset: Offset) -> Option<String> {
75+
for node in nodes {
76+
if let Node::Tag {
77+
name, bits, span, ..
78+
} = node
79+
{
80+
if (name == "extends" || name == "include") && span.contains(offset) {
81+
let template_str = bits.first()?;
82+
let template_name = template_str
83+
.trim()
84+
.trim_start_matches('"')
85+
.trim_end_matches('"')
86+
.trim_start_matches('\'')
87+
.trim_end_matches('\'')
88+
.to_string();
89+
return Some(template_name);
90+
}
91+
}
92+
}
93+
None
94+
}

crates/djls-server/src/ext.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::str::FromStr;
2+
3+
use camino::Utf8PathBuf;
4+
use djls_source::File;
5+
use djls_source::LineCol;
6+
use djls_source::LineIndex;
7+
use djls_source::Offset;
8+
use djls_source::PositionEncoding;
9+
use djls_workspace::paths;
10+
use djls_workspace::Db as WorkspaceDb;
11+
use djls_workspace::TextDocument;
12+
use tower_lsp_server::lsp_types;
13+
use url::Url;
14+
15+
pub(crate) trait PositionExt {
16+
fn to_offset(&self, text: &str, index: &LineIndex, encoding: PositionEncoding) -> Offset;
17+
}
18+
19+
impl PositionExt for lsp_types::Position {
20+
fn to_offset(&self, text: &str, index: &LineIndex, encoding: PositionEncoding) -> Offset {
21+
let line_col = LineCol::new(self.line, self.character);
22+
index.offset(line_col, text, encoding)
23+
}
24+
}
25+
26+
pub(crate) trait TextDocumentIdentifierExt {
27+
fn to_file(&self, db: &mut dyn WorkspaceDb) -> Option<File>;
28+
}
29+
30+
impl TextDocumentIdentifierExt for lsp_types::TextDocumentIdentifier {
31+
fn to_file(&self, db: &mut dyn WorkspaceDb) -> Option<File> {
32+
let path = self.uri.to_utf8_path_buf()?;
33+
Some(db.ensure_file_tracked(&path))
34+
}
35+
}
36+
37+
pub(crate) trait TextDocumentItemExt {
38+
/// Convert LSP `TextDocumentItem` to internal `TextDocument`
39+
fn to_text_document(self) -> TextDocument;
40+
}
41+
42+
impl TextDocumentItemExt for lsp_types::TextDocumentItem {
43+
fn to_text_document(self) -> TextDocument {
44+
TextDocument::new(
45+
self.text,
46+
self.version,
47+
djls_workspace::LanguageId::from(self.language_id.as_str()),
48+
)
49+
}
50+
}
51+
52+
pub(crate) trait UriExt {
53+
/// Convert `uri::Url` to LSP Uri
54+
fn from_url(url: &Url) -> Option<Self>
55+
where
56+
Self: Sized;
57+
58+
/// Convert LSP URI to `url::Url,` logging errors
59+
fn to_url(&self) -> Option<Url>;
60+
61+
/// Convert LSP URI directly to `Utf8PathBuf` (convenience)
62+
fn to_utf8_path_buf(&self) -> Option<Utf8PathBuf>;
63+
}
64+
65+
impl UriExt for lsp_types::Uri {
66+
fn from_url(url: &Url) -> Option<Self> {
67+
let uri_string = url.to_string();
68+
lsp_types::Uri::from_str(&uri_string)
69+
.inspect_err(|e| {
70+
tracing::error!("Failed to convert URL to LSP Uri: {} - Error: {}", url, e);
71+
})
72+
.ok()
73+
}
74+
75+
fn to_url(&self) -> Option<Url> {
76+
Url::parse(self.as_str())
77+
.inspect_err(|e| {
78+
tracing::error!(
79+
"Invalid URI from LSP client: {} - Error: {}",
80+
self.as_str(),
81+
e
82+
);
83+
})
84+
.ok()
85+
}
86+
87+
fn to_utf8_path_buf(&self) -> Option<Utf8PathBuf> {
88+
let url = self.to_url()?;
89+
paths::url_to_path(&url)
90+
}
91+
}

crates/djls-server/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod db;
22
mod encoding;
3+
mod ext;
34
mod logging;
45
mod queue;
56
pub mod server;

0 commit comments

Comments
 (0)