#![allow(missing_docs)]
use std::path::{Path, PathBuf};
use super::{DocumentLocation, Position, Range, SemanticInfo};
use crate::salsa_full::{SymbolKind, Type};
pub struct QueryEngine {
cache: dashmap::DashMap<QueryKey, QueryValue>,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct QueryKey {
kind: QueryKind,
file: PathBuf,
position: Position,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
enum QueryKind {
TypeAt,
Definition,
References,
Implementations,
}
#[derive(Clone, Debug)]
struct QueryValue {
result: Vec<SemanticInfo>,
timestamp: std::time::Instant,
}
impl QueryEngine {
pub fn new() -> Self {
Self {
cache: dashmap::DashMap::new(),
}
}
pub fn type_at(&self, file: &Path, position: Position) -> Option<Type> {
let key = QueryKey {
kind: QueryKind::TypeAt,
file: file.to_path_buf(),
position,
};
if let Some(cached) = self.cache.get(&key) {
return cached.result.first().map(|i| i.ty.clone());
}
let ty = Type::Int;
Some(ty)
}
pub fn goto_definition(&self, file: &Path, position: Position) -> Option<DocumentLocation> {
let key = QueryKey {
kind: QueryKind::Definition,
file: file.to_path_buf(),
position,
};
if let Some(cached) = self.cache.get(&key) {
return cached.result.first().map(|i| i.location.clone());
}
Some(DocumentLocation {
path: file.to_path_buf(),
range: Range::new(Position::new(0, 0), Position::new(0, 10)),
})
}
pub fn find_references(
&self,
file: &Path,
position: Position,
_include_declaration: bool,
) -> Vec<DocumentLocation> {
let key = QueryKey {
kind: QueryKind::References,
file: file.to_path_buf(),
position,
};
if let Some(cached) = self.cache.get(&key) {
return cached.result.iter().map(|i| i.location.clone()).collect();
}
vec![DocumentLocation {
path: file.to_path_buf(),
range: Range::new(
position,
Position::new(position.line, position.character + 5),
),
}]
}
pub fn find_implementations(&self, file: &Path, position: Position) -> Vec<DocumentLocation> {
let key = QueryKey {
kind: QueryKind::Implementations,
file: file.to_path_buf(),
position,
};
if let Some(cached) = self.cache.get(&key) {
return cached.result.iter().map(|i| i.location.clone()).collect();
}
vec![DocumentLocation {
path: file.to_path_buf(),
range: Range::new(Position::new(10, 0), Position::new(20, 10)),
}]
}
pub fn workspace_symbol(&self, query: &str) -> Vec<SymbolInfo> {
vec![SymbolInfo {
name: query.to_string(),
kind: SymbolKind::Function,
location: DocumentLocation {
path: PathBuf::from("main.go"),
range: Range::new(Position::new(0, 0), Position::new(0, 10)),
},
container_name: Some("main".to_string()),
}]
}
pub fn callers(&self, _file: &Path, _position: Position) -> Vec<DocumentLocation> {
vec![]
}
pub fn callees(&self, _file: &Path, _position: Position) -> Vec<DocumentLocation> {
vec![]
}
pub fn semantic_tokens(&self, _file: &Path) -> Vec<SemanticToken> {
vec![]
}
pub fn folding_ranges(&self, _file: &Path) -> Vec<FoldingRange> {
vec![]
}
pub fn document_symbol(&self, _file: &Path) -> Vec<SymbolInfo> {
vec![]
}
pub fn code_lens(&self, _file: &Path) -> Vec<CodeLens> {
vec![]
}
fn invalidate_cache(&self, file: &Path) {
let prefix = file.to_path_buf();
self.cache.retain(|k, _| k.file != prefix);
}
}
impl Default for QueryEngine {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct SymbolInfo {
pub name: String,
pub kind: SymbolKind,
pub location: DocumentLocation,
pub container_name: Option<String>,
}
#[derive(Clone, Debug)]
pub struct SemanticToken {
pub line: usize,
pub character: usize,
pub length: usize,
pub token_type: TokenType,
pub modifiers: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenType {
Namespace,
Type,
Class,
Enum,
Interface,
Struct,
TypeParameter,
Parameter,
Variable,
Property,
EnumMember,
Event,
Function,
Method,
Macro,
Keyword,
Modifier,
Comment,
String,
Number,
Regexp,
Operator,
}
#[derive(Clone, Debug)]
pub struct FoldingRange {
pub start_line: usize,
pub start_character: Option<usize>,
pub end_line: usize,
pub end_character: Option<usize>,
pub kind: FoldingRangeKind,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FoldingRangeKind {
Comment,
Imports,
Region,
}
#[derive(Clone, Debug)]
pub struct CodeLens {
pub range: Range,
pub command: Option<Command>,
pub data: Option<serde_json::Value>,
}
#[derive(Clone, Debug)]
pub struct Command {
pub title: String,
pub command: String,
pub arguments: Option<Vec<serde_json::Value>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_query_engine_creation() {
let engine = QueryEngine::new();
let _ = engine.type_at(Path::new("test.go"), Position::new(0, 0));
}
#[test]
fn test_workspace_symbol() {
let engine = QueryEngine::new();
let symbols = engine.workspace_symbol("main");
assert!(!symbols.is_empty());
}
}