use std::path::Path;
use serde_json::{Value, json};
use crate::lsp::manager::{LspManager, TouchMode};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Operation {
Definition,
References,
Hover,
DocumentSymbol,
WorkspaceSymbol,
Implementation,
PrepareCallHierarchy,
IncomingCalls,
OutgoingCalls,
}
impl Operation {
pub fn parse(s: &str) -> Option<Operation> {
match s {
"definition" | "goToDefinition" => Some(Operation::Definition),
"references" | "findReferences" => Some(Operation::References),
"hover" => Some(Operation::Hover),
"documentSymbol" => Some(Operation::DocumentSymbol),
"workspaceSymbol" => Some(Operation::WorkspaceSymbol),
"implementation" | "goToImplementation" => Some(Operation::Implementation),
"prepareCallHierarchy" => Some(Operation::PrepareCallHierarchy),
"incomingCalls" => Some(Operation::IncomingCalls),
"outgoingCalls" => Some(Operation::OutgoingCalls),
_ => None,
}
}
pub fn needs_position(self) -> bool {
!matches!(self, Operation::DocumentSymbol | Operation::WorkspaceSymbol)
}
}
pub async fn run(
manager: &LspManager,
op: Operation,
path: &Path,
line: u32,
character: u32,
query: &str,
) -> Value {
manager.touch_file(path, TouchMode::Notify).await;
let line = line.saturating_sub(1);
let ch = character.saturating_sub(1);
match op {
Operation::Definition => json!(manager.definition(path, line, ch).await),
Operation::References => json!(manager.references(path, line, ch).await),
Operation::Hover => json!(manager.hover(path, line, ch).await),
Operation::DocumentSymbol => json!(manager.document_symbol(path).await),
Operation::WorkspaceSymbol => json!(manager.workspace_symbol(path, query).await),
Operation::Implementation => json!(manager.implementation(path, line, ch).await),
Operation::PrepareCallHierarchy => {
json!(manager.prepare_call_hierarchy(path, line, ch).await)
}
Operation::IncomingCalls => json!(manager.incoming_calls(path, line, ch).await),
Operation::OutgoingCalls => json!(manager.outgoing_calls(path, line, ch).await),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_accepts_canonical_and_alias_names() {
assert_eq!(Operation::parse("definition"), Some(Operation::Definition));
assert_eq!(
Operation::parse("goToDefinition"),
Some(Operation::Definition)
);
assert_eq!(
Operation::parse("findReferences"),
Some(Operation::References)
);
assert_eq!(
Operation::parse("goToImplementation"),
Some(Operation::Implementation)
);
assert_eq!(Operation::parse("nope"), None);
}
#[test]
fn only_symbol_ops_skip_position() {
assert!(!Operation::DocumentSymbol.needs_position());
assert!(!Operation::WorkspaceSymbol.needs_position());
assert!(Operation::Definition.needs_position());
assert!(Operation::IncomingCalls.needs_position());
}
}