Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/manganis/manganis-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ fn resolve_path(raw: &str, span: Span) -> Result<PathBuf, AssetParseError> {
if let Some(local_folder) = span.local_file().as_ref().and_then(|f| f.parent()) {
local_folder.join(raw)
} else {
// If we are running in rust analyzer, just assume the path is valid and return an error when
// we compile if it doesn't exist
if looks_like_rust_analyzer(&span) {
return Ok(
"The asset macro was expanded under Rust Analyzer which doesn't support paths or local assets yet"
.into(),
);
}

// Otherwise, return an error about the version of rust required for relative assets
return Err(AssetParseError::RelativeAssetPath);
}
} else {
Expand Down Expand Up @@ -328,3 +338,22 @@ impl std::fmt::Display for AssetParseError {
}
}
}

/// Rust analyzer doesn't provide a stable way to detect if macros are running under it.
/// This function uses heuristics to determine if we are running under rust analyzer for better error
/// messages.
fn looks_like_rust_analyzer(span: &Span) -> bool {
// Rust analyzer spans have a struct debug impl compared to rustcs custom debug impl
// RA Example: SpanData { range: 45..58, anchor: SpanAnchor(EditionedFileId(0, Edition2024), ErasedFileAstId { kind: Fn, index: 0, hash: 9CD8 }), ctx: SyntaxContext(4294967036) }
// Rustc Example: #0 bytes(70..83)
let looks_like_rust_analyzer_span = format!("{:?}", span).contains("ctx:");
// The rust analyzer macro expander runs under RUST_ANALYZER_INTERNALS_DO_NOT_USE
let looks_like_rust_analyzer_env = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE").is_ok();
// The rust analyzer executable is named rust-analyzer-proc-macro-srv
let looks_like_rust_analyzer_exe = std::env::current_exe().ok().is_some_and(|p| {
p.file_stem()
.and_then(|s| s.to_str())
.is_some_and(|s| s.contains("rust-analyzer"))
});
looks_like_rust_analyzer_span || looks_like_rust_analyzer_env || looks_like_rust_analyzer_exe
}
Loading