use std::collections::VecDeque;
use std::sync::mpsc::{channel, Receiver, RecvError, Sender, TryRecvError};
use std::thread;
use url::Url;
use languageserver_types::{Position, Range};
pub type TaskId = usize;
#[derive(Debug)]
pub enum QueryRequest {
TypeAtPosition(TaskId, Url, Position),
RenameAtPosition(TaskId, Url, Position, String),
DefinitionAtPosition(TaskId, Url, Position),
ReferencesAtPosition(TaskId, Url, Position, bool),
OpenFile(Url, String),
EditFile(Url, Vec<(Range, String)>),
Initialize(TaskId),
}
impl QueryRequest {
pub fn is_mutation(&self) -> bool {
match self {
QueryRequest::OpenFile(..)
| QueryRequest::EditFile(..)
| QueryRequest::RenameAtPosition(..)
| QueryRequest::Initialize(..) => true,
QueryRequest::TypeAtPosition(..) => false,
QueryRequest::DefinitionAtPosition(..) => false,
QueryRequest::ReferencesAtPosition(..) => false,
}
}
}
pub enum LspResponse {
Type(TaskId, String),
Range(TaskId, Url, Range),
Ranges(TaskId, Vec<(Url, Range)>),
WorkspaceEdits(TaskId, Vec<(Url, Range, String)>),
Completions(TaskId, Vec<(String, String)>),
Initialized(TaskId),
Nothing(TaskId),
Diagnostics(Url, Vec<(Range, String)>),
}
pub trait Actor {
type InMessage: Send + Sync + 'static;
fn receive_messages(&mut self, messages: &mut VecDeque<Self::InMessage>);
}
pub struct ActorControl<MessageType: Send + Sync + 'static> {
pub channel: Sender<MessageType>,
pub join_handle: std::thread::JoinHandle<()>,
}
pub fn spawn_actor<T: Actor + Send + 'static>(mut actor: T) -> ActorControl<T::InMessage> {
let (actor_tx, actor_rx) = channel();
let mut message_queue = VecDeque::default();
let handle = thread::spawn(move || loop {
match push_all_pending(&actor_rx, &mut message_queue) {
Ok(()) => {
actor.receive_messages(&mut message_queue);
}
Err(error) => {
match error {
PushAllPendingError::Disconnected => {
eprintln!("Failure during top-level message receive");
}
}
break;
}
}
});
ActorControl {
channel: actor_tx,
join_handle: handle,
}
}
enum PushAllPendingError {
Disconnected,
}
fn push_all_pending<T>(rx: &Receiver<T>, vec: &mut VecDeque<T>) -> Result<(), PushAllPendingError> {
if vec.is_empty() {
match rx.recv() {
Ok(m) => vec.push_back(m),
Err(RecvError) => return Err(PushAllPendingError::Disconnected),
}
}
loop {
match rx.try_recv() {
Ok(m) => vec.push_back(m),
Err(TryRecvError::Empty) => break Ok(()),
Err(TryRecvError::Disconnected) => break Err(PushAllPendingError::Disconnected),
}
}
}