MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / handle_completion

Method handle_completion

src/completion/handler.rs:261–457  ·  view source on GitHub ↗

Main completion handler — called by `LanguageServer::completion`. Tries each completion strategy in priority order and returns the first one that produces results. Falls back to no completions when nothing matches.

(
        &self,
        params: CompletionParams,
    )

Source from the content-addressed store, hash-verified

259 /// first one that produces results. Falls back to no completions
260 /// when nothing matches.
261 pub(crate) async fn handle_completion(
262 &self,
263 params: CompletionParams,
264 ) -> Result<Option<CompletionResponse>> {
265 let uri = params.text_document_position.text_document.uri.to_string();
266 let mut position = params.text_document_position.position;
267
268 // Get file content for offset calculation. For Blade files,
269 // use the virtual PHP content and translate the cursor position
270 // so that variable resolution walks the preprocessed AST.
271 let content = if self.is_blade_file(&uri) {
272 let vc = self.blade_virtual_content.read();
273 if let Some(virtual_php) = vc.get(&uri) {
274 position = self.translate_blade_to_php(&uri, position);
275 Some(virtual_php.clone())
276 } else {
277 self.get_file_content(&uri)
278 }
279 } else {
280 self.get_file_content(&uri)
281 };
282
283 if let Some(content) = content {
284 // Activate the chain resolution cache so that shared chain
285 // prefixes are resolved once and reused within this completion
286 // request. The guard is re-entrant safe.
287 let _chain_guard = super::resolver::with_chain_resolution_cache();
288 let _body_infer_guard = self.activate_body_return_inferrer();
289
290 // Gather per-file context (classes, use-map, namespace) in one
291 // call instead of three separate lock-and-unwrap blocks.
292 // Use the cursor offset for position-aware namespace resolution
293 // so that multi-namespace files resolve to the correct namespace.
294 let cursor_offset = crate::util::position_to_offset(&content, position);
295 let ctx = self.file_context_at(&uri, cursor_offset);
296
297 // ── Suppress completion inside non-doc comments ─────────
298 if crate::completion::comment_position::is_inside_non_doc_comment(&content, position) {
299 return Ok(None);
300 }
301
302 // ── PHPDoc block generation on `/**` ────────────────────
303 // When the user types `/**` above a declaration, generate
304 // a complete docblock skeleton as a single snippet item.
305 // Must run before the docblock-interior checks below.
306 {
307 let class_loader = self.class_loader(&ctx);
308 let function_loader = self.function_loader(&ctx);
309 if let Some(response) = crate::completion::phpdoc::generation::try_generate_docblock(
310 &content,
311 position,
312 &ctx.use_map,
313 &ctx.namespace,
314 &ctx.classes,
315 &class_loader,
316 Some(&function_loader),
317 ) {
318 return Ok(Some(response));

Callers 1

completionMethod · 0.80

Calls 15

try_generate_docblockFunction · 0.85
extract_phpdoc_prefixFunction · 0.85
is_inside_docblockFunction · 0.85
detect_type_hint_contextFunction · 0.85
classify_string_contextFunction · 0.85
is_blade_fileMethod · 0.80
cloneMethod · 0.80
get_file_contentMethod · 0.80

Tested by

no test coverage detected