Build a `CompletionItem` for a class name completion. This is the **single authority** for the visual presentation of class name completions. When the typed prefix contains no namespace separator (e.g. `Order`, `Exc`), the label is the **short name** and the namespace is shown via `label_details.description`, giving a clean two-column layout: ```text Order App\Models Order
(
&self,
texts: ClassItemTexts,
fqn: &str,
source_tier: char,
demoted: bool,
ctor_params: Option<&[ParameterInfo]>,
is_deprecated: bool,
)
| 1188 | /// `demoted` using the affinity table and quality prefix stored |
| 1189 | /// in `ClassItemCtx`. |
| 1190 | pub(in crate::completion) fn build_item( |
| 1191 | &self, |
| 1192 | texts: ClassItemTexts, |
| 1193 | fqn: &str, |
| 1194 | source_tier: char, |
| 1195 | demoted: bool, |
| 1196 | ctor_params: Option<&[ParameterInfo]>, |
| 1197 | is_deprecated: bool, |
| 1198 | ) -> CompletionItem { |
| 1199 | let short_name = crate::util::short_name(fqn); |
| 1200 | let sort_text = class_sort_text( |
| 1201 | short_name, |
| 1202 | fqn, |
| 1203 | &self.quality_prefix, |
| 1204 | source_tier, |
| 1205 | demoted, |
| 1206 | &self.affinity_table, |
| 1207 | ); |
| 1208 | let (insert_text, insert_text_format) = if self.is_attribute { |
| 1209 | let snippet = crate::completion::builder::build_attribute_snippet( |
| 1210 | &texts.base_name, |
| 1211 | ctor_params.unwrap_or(&[]), |
| 1212 | ); |
| 1213 | if snippet.contains("$0") { |
| 1214 | (snippet, Some(InsertTextFormat::SNIPPET)) |
| 1215 | } else { |
| 1216 | // No constructor params — bare name, no snippet syntax. |
| 1217 | (snippet, None) |
| 1218 | } |
| 1219 | } else if self.is_new { |
| 1220 | Backend::build_new_insert(&texts.base_name, ctor_params) |
| 1221 | } else { |
| 1222 | (texts.base_name, None) |
| 1223 | }; |
| 1224 | // When the typed prefix is a simple name (no `\`), use the |
| 1225 | // short name as filter_text so the editor's fuzzy scorer |
| 1226 | // ranks candidates by short-name relevance. With the FQN as |
| 1227 | // filter_text, the editor finds accidental substring hits |
| 1228 | // inside namespace paths (e.g. "Order" matching inside |
| 1229 | // "Mockery\HigherOrderMessage") and may promote them above |
| 1230 | // genuine prefix matches. In FQN mode with a namespace- |
| 1231 | // qualified prefix (e.g. `use Illuminate\D`), keep the |
| 1232 | // original filter_text so namespace drilling works. |
| 1233 | // |
| 1234 | // In the same non-FQN case, set the label to the short name |
| 1235 | // and show the namespace in `label_details.description`. |
| 1236 | // This gives a clean two-column layout in the editor popup: |
| 1237 | // |
| 1238 | // Order App\Models |
| 1239 | // Order Luxplus\Database\Model\Orders |
| 1240 | // |
| 1241 | // so users can distinguish same-named classes without the |
| 1242 | // label being a long FQN that the editor truncates. |
| 1243 | let (label, filter_text, label_details) = if self.prefix_has_namespace { |
| 1244 | (fqn.to_string(), texts.filter, None) |
| 1245 | } else { |
| 1246 | let ns = fqn.rsplit_once('\\').map(|(ns, _)| ns.to_string()); |
| 1247 | ( |
no test coverage detected