Skip to content

Commit

Permalink
fix lsp rpc loop, and add lsp_types
Browse files Browse the repository at this point in the history
  • Loading branch information
oysandvik94 committed Sep 3, 2024
1 parent a928034 commit 335ccba
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 68 deletions.
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/son_of_anton/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ anyhow = { workspace = true }
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.122"
tracing-appender = "0.2.3"
lsp-types = "0.97.0"
32 changes: 25 additions & 7 deletions crates/son_of_anton/src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ pub mod initialize;

use std::io::{Stdout, Write};

use anyhow::anyhow;
use anyhow::Result;
use initialize::{InitalizeParams, InitializeResponse};
use lsp_types::{InitializeParams, InitializedParams};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::from_str;
use tracing::{event, Level};
Expand All @@ -22,13 +23,28 @@ impl SonOfAnton {
pub fn handle_message(&mut self, lsp_request: LspRequest) -> Result<()> {
match lsp_request.request.method.as_str() {
"initialize" => {
let _ = fun_name::<InitalizeParams>(&lsp_request)?;
let params: InitializeParams =
deserialize_request::<InitializeParams>(&lsp_request)?;

let resp: InitializeResponse = initialize::handle_initialize();
let client_name = match params.client_info {
Some(info) => info.name,
None => "Unknown client".to_owned(),
};

event!(Level::INFO, "Initializing with client: {client_name}");
let resp = initialize::handle_initialize();
self.send_response(lsp_request, resp)?;
}
_ => {
event!(Level::DEBUG, "Received unknown request from server",);
"initialized" => {
let _ = deserialize_request::<InitializedParams>(&lsp_request)?;
event!(Level::INFO, "Server was initialized");
}
unknown_method => {
event!(
Level::DEBUG,
"Received unknown request from server: method = {}",
unknown_method
);
}
}

Expand Down Expand Up @@ -56,7 +72,7 @@ impl SonOfAnton {
}
}

fn fun_name<T>(lsp_request: &LspRequest) -> Result<Option<T>>
fn deserialize_request<T>(lsp_request: &LspRequest) -> Result<T>
where
T: DeserializeOwned + std::fmt::Debug,
{
Expand All @@ -66,5 +82,7 @@ where
"Received request from server: {:?}",
deserialized_request
);
Ok(deserialized_request.params)
deserialized_request
.params
.ok_or_else(|| anyhow!("Expected params to be Some, but got None"))
}
47 changes: 8 additions & 39 deletions crates/son_of_anton/src/lsp/initialize.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,14 @@
use serde::{Deserialize, Serialize};
use lsp_types::{HoverProviderCapability, InitializeResult, ServerCapabilities, ServerInfo};

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct InitalizeParams {
client_info: Option<ClientInfo>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ClientInfo {
pub name: String,
pub version: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct InitializeResponse {
capabilities: ServerCapabilities,
server_info: ServerInfo,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ServerCapabilities {
hover_provider: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ServerInfo {
name: String,
version: String,
}

pub fn handle_initialize() -> InitializeResponse {
InitializeResponse {
pub fn handle_initialize() -> InitializeResult {
InitializeResult {
capabilities: ServerCapabilities {
hover_provider: Some(true),
hover_provider: Some(HoverProviderCapability::Simple(true)),
..Default::default()
},
server_info: ServerInfo {
server_info: Some(ServerInfo {
name: "Son of Anton".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
},
version: Some(env!("CARGO_PKG_VERSION").to_string()),
}),
}
}
48 changes: 26 additions & 22 deletions crates/son_of_anton/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::{self, BufRead};

use anyhow::{anyhow, Result};
use anyhow::{Context, Result};
use serde_json::from_str;
use son_of_anton::{
logging::setup_logging,
Expand All @@ -12,40 +12,42 @@ use tracing::{event, Level};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _guard = setup_logging()?;

event!(Level::INFO, "Starting son of anton");
event!(
Level::INFO,
r#"
Starting Son of Anton...
____ ___ _ _
/ ___|___ _ __ / _ \ / \ _ __| |_ ___ _ __
| | / _ \| '_ \ | | | |/ _ \ | '__| __/ _ \| '_ \
| |__| (_) | | | || |_| / ___ \| | | || (_) | | | |
\____\___/|_| |_(_)___/_/ \_\_| \__\___/|_| |_|
"#
);

let mut reader = io::stdin().lock();
let mut anton = SonOfAnton::from(io::stdout());

loop {
let mut buffer = String::new();
reader.read_line(&mut buffer)?;

if buffer.trim().is_empty() {
continue;
}

match process_message(&mut buffer.as_bytes(), &mut anton) {
Ok(()) => {
continue;
match process_message(&mut reader) {
Ok(request) => {
anton.handle_message(request)?;
}
Err(e) => {
event!(Level::ERROR, "Error processing message: {:?}", e);
let mut buffer = String::new();
reader.read_line(&mut buffer)?;
event!(Level::ERROR, "Remaining content was {:?}", buffer);
}
}
}
}

fn process_message(
reader: &mut impl BufRead,
anton: &mut SonOfAnton,
) -> Result<(), Box<dyn std::error::Error>> {
fn process_message(reader: &mut impl BufRead) -> Result<LspRequest, Box<dyn std::error::Error>> {
let content_length = read_until_content_length(reader)?;
read_until_carriage_return(reader);

let request = read_message(content_length, reader)?;
anton.handle_message(request)?;
Ok(())
Ok(request)
}

fn read_message(content_length: u64, reader: &mut impl BufRead) -> Result<LspRequest> {
Expand All @@ -66,12 +68,15 @@ fn read_message(content_length: u64, reader: &mut impl BufRead) -> Result<LspReq

fn read_content(content_length: u64, reader: &mut impl BufRead) -> Result<String, anyhow::Error> {
let mut buffer = vec![0; content_length as usize];
reader.read_exact(&mut buffer)?;
reader
.read_exact(&mut buffer)
.context("Error while reading content based on content_length")?;
let content = String::from_utf8(buffer)?;
Ok(content)
}

fn read_until_carriage_return(reader: &mut impl BufRead) {
event!(Level::TRACE, "Reading until carriage return");
for line in reader.lines().map_while(Result::ok) {
if line.is_empty() {
return;
Expand All @@ -81,16 +86,16 @@ fn read_until_carriage_return(reader: &mut impl BufRead) {

fn read_until_content_length(reader: &mut impl BufRead) -> Result<u64> {
for line in reader.lines() {
event!(Level::INFO, "finding content length");
let line = line?;

let content_length = parse_headers(&line);
if let Some(content_length) = content_length {
event!(Level::TRACE, "Found content length {:?} ", content_length);
return Ok(content_length);
}
}

Err(anyhow!("Never retrieved content length"))
panic!("Never received content length, assume server has died")
}

fn parse_headers(line: &str) -> Option<u64> {
Expand All @@ -99,7 +104,6 @@ fn parse_headers(line: &str) -> Option<u64> {
let key = header[0].trim();
if key == "Content-Length" {
let parsed_header = header[1].trim().parse::<usize>();
event!(Level::DEBUG, "split header: {:?}", parsed_header);
if let Ok(parsed_header) = parsed_header {
return Some(parsed_header as u64);
}
Expand Down

0 comments on commit 335ccba

Please sign in to comment.