diff --git a/crates/djls-server/src/completions.rs b/crates/djls-server/src/completions.rs index 093faa3..2a64bcc 100644 --- a/crates/djls-server/src/completions.rs +++ b/crates/djls-server/src/completions.rs @@ -4,7 +4,10 @@ //! and generating appropriate completion items for Django templates. use djls_project::TemplateTags; -use djls_templates::templatetags::generate_snippet_for_tag; +use djls_templates::templatetags::generate_partial_snippet; +use djls_templates::templatetags::generate_snippet_for_tag_with_end; +use djls_templates::templatetags::ArgType; +use djls_templates::templatetags::SimpleArgType; use djls_templates::templatetags::TagSpecs; use djls_workspace::FileKind; use djls_workspace::PositionEncoding; @@ -19,7 +22,7 @@ use tower_lsp_server::lsp_types::Position; /// /// Used to determine whether the completion system needs to insert /// closing braces when completing a Django template tag. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq)] pub enum ClosingBrace { /// No closing brace present - need to add full `%}` or `}}` None, @@ -29,18 +32,56 @@ pub enum ClosingBrace { FullClose, } -/// Cursor context within a Django template tag for completion support. +/// Rich context-aware completion information for Django templates. /// -/// Captures the state around the cursor position to provide intelligent -/// completions and determine what text needs to be inserted. -#[derive(Debug)] -pub struct TemplateTagContext { - /// The partial tag text before the cursor (e.g., "loa" for "{% loa|") - pub partial_tag: String, - /// What closing characters are already present after the cursor - pub closing_brace: ClosingBrace, - /// Whether a space is needed before the completion (true if cursor is right after `{%`) - pub needs_leading_space: bool, +/// Distinguishes between different completion contexts to provide +/// appropriate suggestions based on cursor position. +#[derive(Debug, Clone, PartialEq)] +#[allow(dead_code)] +pub enum TemplateCompletionContext { + /// Completing a tag name after {% + TagName { + /// Partial tag name typed so far + partial: String, + /// Whether a space is needed before the tag name + needs_space: bool, + /// What closing characters are present + closing: ClosingBrace, + }, + /// Completing arguments within a tag + TagArgument { + /// The tag name + tag: String, + /// Position in the argument list (0-based) + position: usize, + /// Partial text for current argument + partial: String, + /// Arguments already parsed before cursor + parsed_args: Vec, + /// What closing characters are present + closing: ClosingBrace, + }, + /// Completing a library name after {% load + LibraryName { + /// Partial library name typed so far + partial: String, + /// What closing characters are present + closing: ClosingBrace, + }, + /// TODO: Future - completing filters after | + Filter { + /// Partial filter name typed so far + partial: String, + }, + /// TODO: Future - completing variables after {{ + Variable { + /// Partial variable name typed so far + partial: String, + /// What closing characters are present + closing: ClosingBrace, + }, + /// No template context found + None, } /// Information about a line of text and cursor position within it @@ -129,7 +170,7 @@ fn get_line_info( } /// Analyze a line of template text to determine completion context -fn analyze_template_context(line: &str, cursor_offset: usize) -> Option { +fn analyze_template_context(line: &str, cursor_offset: usize) -> Option { // Find the last {% before cursor position let prefix = &line[..cursor_offset.min(line.len())]; let tag_start = prefix.rfind("{%")?; @@ -138,20 +179,86 @@ fn analyze_template_context(line: &str, cursor_offset: usize) -> Option