use std::sync::Arc;
use tower_lsp::lsp_types::*;
use crate::types::ClassInfo;
pub(crate) type ByteRange = (usize, usize);
pub(crate) fn compute_use_line_ranges(content: &str) -> Vec<ByteRange> {
let mut ranges = Vec::new();
let mut offset: usize = 0;
let mut brace_depth: usize = 0;
let mut namespace_brace_depth: Option<usize> = None;
for line in content.split('\n') {
let code = line.split("//").next().unwrap_or(line);
let code = code.split('#').next().unwrap_or(code);
let trimmed = line.trim_start();
if trimmed.starts_with("namespace ") && code.contains('{') {
namespace_brace_depth = Some(brace_depth);
}
for ch in code.chars() {
match ch {
'{' => brace_depth += 1,
'}' => {
brace_depth = brace_depth.saturating_sub(1);
if namespace_brace_depth == Some(brace_depth) {
namespace_brace_depth = None;
}
}
_ => {}
}
}
let top_level_depth = namespace_brace_depth.map_or(0, |d| d + 1);
if trimmed.starts_with("use ") && trimmed.contains(';') && brace_depth == top_level_depth {
ranges.push((offset, offset + line.len()));
}
offset += line.len() + 1; }
ranges
}
pub(crate) fn is_offset_in_ranges(offset: u32, ranges: &[ByteRange]) -> bool {
let offset = offset as usize;
ranges
.iter()
.any(|&(start, end)| offset >= start && offset < end)
}
pub(crate) use crate::util::resolve_to_fqn;
pub(crate) fn find_innermost_enclosing_class(
local_classes: &[Arc<ClassInfo>],
offset: u32,
) -> Option<&ClassInfo> {
local_classes
.iter()
.filter(|c| offset >= c.start_offset && offset <= c.end_offset)
.min_by_key(|c| c.end_offset.saturating_sub(c.start_offset))
.map(|c| c.as_ref())
}
pub(crate) fn make_diagnostic(
range: Range,
severity: DiagnosticSeverity,
code: &str,
message: String,
) -> Diagnostic {
Diagnostic {
range,
severity: Some(severity),
code: Some(NumberOrString::String(code.to_string())),
code_description: None,
source: Some("phpantom".to_string()),
message,
related_information: None,
tags: None,
data: None,
}
}