A simple tool kit helping you create language server with Rust

45 points PrivateRookie

Some time ago I used lsp-server to implement a language server, it is very good, but I am not very comfortable with it, especially I need to write a lot of turbo fish symbols, and manual match Method fields. I hope it can handle http requests like what I have done in warp or other http frameworks, and do not need to write a lot of turbo fish symbols. So I wrote a lsp development tool kit, which provides a simple example in the project, installation is included in README.md file.

here is how my crate handle lsp request in demo

// pass context when handle request need;
req.with(self)
// pass handler function, you must specify param type
// in anonymous handler function argument, other wise
// you have to use turbo fish symbol
.then(|ctx, id, _: InitializeParams| {
    let ret = InitializeResult {
        capabilities: ServerCapabilities {
            completion_provider: Some(CompletionOptions {
                all_commit_characters: None,
                resolve_provider: None,
                trigger_characters: Some(vec!["$".to_string()]),
                work_done_progress: None,
            }),
            ..Default::default()
        },
        server_info: Some(InitializeResultServerInfo {
            name: "yaya-server".to_string(),
            version: Some("0.0.1".to_string()),
        }),
    };
    ctx.resp(id.ok_resp(ret))
})
// use or_else to route to other handler function if
// method do not match
.or_else(|ctx, id, _: CompletionParams| {
    let item = CompletionItem {
        label: "demo".to_string(),
        detail: Some("that's ok".to_string()),
        insert_text: Some("yaya".to_string()),
        kind: Some(CompletionItemKind::Keyword),
        ..Default::default()
    };
    ctx.resp(id.ok_resp(vec![item]))
})
.or_else(|ctx, id, _: ShutdownParams| {
    ctx.terminated = true;
    tracing::info!("shutting down...");
    ctx.resp(id.ok_resp(Empty {}))
})
// finally handle default req
.unify(|req| {
    let (req, ctx) = req.split();
    tracing::warn!("unhandled {:#?}", req);
    ctx.resp(req.id.ok_resp(serde_json::Value::Null))
})

with less than 200 lines of rust code, we implement a dummy lsp server which provides dummy completion

​

demo

Hope this crates will help when implementing LSP server, happy coding :)