use lsp_types::{OneOf, SymbolKind, WorkspaceSymbol};
use serde::{Deserialize, Serialize};
use tracing::warn;
use crate::symbol::FileLocation;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Symbol {
pub name: String,
pub kind: SymbolKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub container_name: Option<String>,
pub location: FileLocation,
}
impl Symbol {
#[allow(dead_code)]
pub fn new(
name: String,
kind: SymbolKind,
container_name: Option<String>,
location: FileLocation,
) -> Self {
Self {
name,
kind,
container_name,
location,
}
}
}
impl From<WorkspaceSymbol> for Symbol {
fn from(ws_symbol: WorkspaceSymbol) -> Self {
let location = match ws_symbol.location {
OneOf::Left(location) => FileLocation::from(&location),
OneOf::Right(_workspace_symbol) => {
warn!("WorkspaceSymbol location variant not supported, using empty location");
FileLocation {
file_path: std::path::PathBuf::new(),
range: crate::symbol::location::Range {
start: crate::symbol::location::Position { line: 0, column: 0 },
end: crate::symbol::location::Position { line: 0, column: 0 },
},
}
}
};
Self {
name: ws_symbol.name,
kind: ws_symbol.kind,
container_name: ws_symbol.container_name,
location,
}
}
}
impl From<(&lsp_types::DocumentSymbol, &std::path::Path)> for Symbol {
fn from((doc_symbol, file_path): (&lsp_types::DocumentSymbol, &std::path::Path)) -> Self {
use crate::symbol::location::Range as SymRange;
Self {
name: doc_symbol.name.clone(),
kind: doc_symbol.kind,
container_name: None, location: FileLocation {
file_path: file_path.to_path_buf(),
range: SymRange::from(doc_symbol.selection_range),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use lsp_types::{Location, Position, Range, Uri};
use std::str::FromStr;
#[test]
fn test_symbol_creation() {
use crate::symbol::location::{FileLocation, Position as SymPosition, Range as SymRange};
use std::path::PathBuf;
let location = FileLocation {
file_path: PathBuf::from("/path/to/file.cpp"),
range: SymRange {
start: SymPosition {
line: 10,
column: 5,
},
end: SymPosition {
line: 10,
column: 20,
},
},
};
let symbol = Symbol::new(
"test_function".to_string(),
SymbolKind::FUNCTION,
Some("TestClass".to_string()),
location.clone(),
);
assert_eq!(symbol.name, "test_function");
assert_eq!(symbol.kind, SymbolKind::FUNCTION);
assert_eq!(symbol.container_name, Some("TestClass".to_string()));
assert_eq!(symbol.location, location);
}
#[test]
fn test_from_workspace_symbol_with_location() {
use std::path::PathBuf;
let uri = Uri::from_str("file:///path/to/test.cpp").unwrap();
let location = Location {
uri,
range: Range {
start: Position {
line: 0,
character: 0,
},
end: Position {
line: 0,
character: 10,
},
},
};
let ws_symbol = WorkspaceSymbol {
name: "Math".to_string(),
kind: SymbolKind::CLASS,
tags: None,
container_name: Some("TestProject".to_string()),
location: OneOf::Left(location),
data: None,
};
let symbol = Symbol::from(ws_symbol);
assert_eq!(symbol.name, "Math");
assert_eq!(symbol.kind, SymbolKind::CLASS);
assert_eq!(symbol.container_name, Some("TestProject".to_string()));
assert_eq!(
symbol.location.file_path,
PathBuf::from("/path/to/test.cpp")
);
assert_eq!(symbol.location.range.start.line, 0);
assert_eq!(symbol.location.range.start.column, 0);
assert_eq!(symbol.location.range.end.line, 0);
assert_eq!(symbol.location.range.end.column, 10);
}
}