//! Virtual documents: read-only contents a language server provides for a //! non-`file:` URI (library classes from `jdt://`, `workspace/textDocumentContent`). use percent_encoding::percent_decode_str; /// Markers decompilers / disassemblers put at the top of generated code. const GENERATED_MARKERS: [&str; 5] = [ "generated by the fernflower decompiler", "failed to get sources", "decompiled with cfr", "decompiled with procyon", "generated by the disassembler", ]; /// Whether `text` is decompiled / disassembled code rather than real source. pub fn is_decompiled(text: &str) -> bool { let head: String = text.chars().take(600).collect::().to_ascii_lowercase(); GENERATED_MARKERS.iter().any(|m| head.contains(m)) } /// `scheme` of a URI (`jdt` for `jdt://…`). pub fn scheme(uri: &str) -> &str { uri.split_once(':').map(|(s, _)| s).unwrap_or("") } /// The URI's path segments (without query / fragment), percent-decoded. fn segments(uri: &str) -> Vec { let rest = uri.split_once(':').map(|(_, r)| r).unwrap_or(uri); let rest = rest.split(['?', '#']).next().unwrap_or(rest); let rest = rest.strip_prefix("//").unwrap_or(rest); rest.split('/').filter(|s| !s.is_empty()).map(|s| percent_decode_str(s).decode_utf8_lossy().into_owned()).collect() } /// Editor tab title: the last path segment; a class file whose real source /// was found is shown as `.java` (IDEA: `String.java` vs `String.class`). pub fn title(uri: &str, decompiled: bool) -> String { let name = segments(uri).pop().unwrap_or_else(|| uri.to_owned()); match name.strip_suffix(".class") { Some(stem) if !decompiled && scheme(uri) == "jdt" => format!("{stem}.java"), _ => name, } } /// Where the document comes from, e.g. the jar path of a `jdt://` class. pub fn description(uri: &str) -> Option { if scheme(uri) != "jdt" { return None; } let segs = segments(uri); // jdt://contents///?=/