Detect whether the cursor is immediately after a `/**` trigger and, if so, generate a full docblock completion item. Returns `None` when the cursor is not at a `/**` trigger position or when the declaration below cannot be identified.
(
content: &str,
position: Position,
use_map: &HashMap<String, String>,
file_namespace: &Option<String>,
local_classes: &[Arc<ClassInfo>],
class_loader: &dyn Fn(&str) -> Option
| 61 | /// Returns `None` when the cursor is not at a `/**` trigger position or |
| 62 | /// when the declaration below cannot be identified. |
| 63 | pub fn try_generate_docblock( |
| 64 | content: &str, |
| 65 | position: Position, |
| 66 | use_map: &HashMap<String, String>, |
| 67 | file_namespace: &Option<String>, |
| 68 | local_classes: &[Arc<ClassInfo>], |
| 69 | class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>, |
| 70 | function_loader: FunctionLoader<'_>, |
| 71 | ) -> Option<CompletionResponse> { |
| 72 | let (trigger_range, indent) = detect_docblock_trigger(content, position)?; |
| 73 | |
| 74 | // Find the declaration below and classify it. |
| 75 | let remaining = get_text_after_trigger(content, position); |
| 76 | let context = classify_declaration(&remaining); |
| 77 | |
| 78 | // Inside a function body (Inline / Unknown) we don't generate a |
| 79 | // full docblock — the `@` tag completion is more appropriate there |
| 80 | // because the user might want @var, @throws, @todo, etc. |
| 81 | if matches!(context, DocblockContext::Inline | DocblockContext::Unknown) { |
| 82 | return None; |
| 83 | } |
| 84 | |
| 85 | let mut sym = parse_declaration_info(&remaining); |
| 86 | |
| 87 | // For untyped properties, try to fill in the type from the parsed |
| 88 | // class data (e.g. constructor-inferred `$this->prop = new Foo()`). |
| 89 | if matches!(context, DocblockContext::Property) && sym.type_hint.is_none() { |
| 90 | enrich_property_type_from_class(&mut sym, content, position, local_classes); |
| 91 | } |
| 92 | |
| 93 | let snippet = build_docblock_snippet( |
| 94 | &context, |
| 95 | &sym, |
| 96 | &indent, |
| 97 | content, |
| 98 | position, |
| 99 | use_map, |
| 100 | file_namespace, |
| 101 | local_classes, |
| 102 | class_loader, |
| 103 | function_loader, |
| 104 | ); |
| 105 | |
| 106 | if snippet.is_empty() { |
| 107 | return None; |
| 108 | } |
| 109 | |
| 110 | // Collect additional text edits (e.g. use imports for @throws). |
| 111 | let additional_edits = build_throws_import_edits( |
| 112 | content, |
| 113 | position, |
| 114 | use_map, |
| 115 | file_namespace, |
| 116 | &context, |
| 117 | class_loader, |
| 118 | function_loader, |
| 119 | ); |
| 120 |
no test coverage detected