lsp: Use one common Error type (where possible)

This commit is contained in:
Tobias Hunger 2023-08-29 10:43:10 +02:00 committed by Tobias Hunger
parent b1e1cd1881
commit d5cc147644
5 changed files with 45 additions and 64 deletions

View file

@ -5,6 +5,9 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub type Error = Box<dyn std::error::Error>;
pub type Result<T> = std::result::Result<T, Error>;
/// API used by the LSP to talk to the Preview. The other direction uses the /// API used by the LSP to talk to the Preview. The other direction uses the
/// ServerNotifier /// ServerNotifier
pub trait PreviewApi { pub trait PreviewApi {
@ -13,11 +16,7 @@ pub trait PreviewApi {
fn set_contents(&self, path: &Path, contents: &str); fn set_contents(&self, path: &Path, contents: &str);
fn load_preview(&self, component: PreviewComponent, behavior: PostLoadBehavior); fn load_preview(&self, component: PreviewComponent, behavior: PostLoadBehavior);
fn config_changed(&self, style: &str, include_paths: &[PathBuf]); fn config_changed(&self, style: &str, include_paths: &[PathBuf]);
fn highlight( fn highlight(&self, path: Option<PathBuf>, offset: u32) -> Result<()>;
&self,
path: Option<PathBuf>,
offset: u32,
) -> Result<(), Box<dyn std::error::Error>>;
} }
/// The Component to preview /// The Component to preview

View file

@ -10,7 +10,7 @@ mod semantic_tokens;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use crate::common::PreviewApi; use crate::common::{PreviewApi, Result};
use crate::util::{map_node, map_range, map_token, to_lsp_diag}; use crate::util::{map_node, map_range, map_token, to_lsp_diag};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -40,8 +40,6 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
pub type Error = Box<dyn std::error::Error>;
const QUERY_PROPERTIES_COMMAND: &str = "slint/queryProperties"; const QUERY_PROPERTIES_COMMAND: &str = "slint/queryProperties";
const REMOVE_BINDING_COMMAND: &str = "slint/removeBinding"; const REMOVE_BINDING_COMMAND: &str = "slint/removeBinding";
const SHOW_PREVIEW_COMMAND: &str = "slint/showPreview"; const SHOW_PREVIEW_COMMAND: &str = "slint/showPreview";
@ -109,7 +107,7 @@ pub struct RequestHandler(
dyn Fn( dyn Fn(
serde_json::Value, serde_json::Value,
Rc<Context>, Rc<Context>,
) -> Pin<Box<dyn Future<Output = Result<serde_json::Value, Error>>>>, ) -> Pin<Box<dyn Future<Output = Result<serde_json::Value>>>>,
>, >,
>, >,
); );
@ -117,7 +115,7 @@ pub struct RequestHandler(
impl RequestHandler { impl RequestHandler {
pub fn register< pub fn register<
R: lsp_types::request::Request, R: lsp_types::request::Request,
Fut: Future<Output = Result<R::Result, Error>> + 'static, Fut: Future<Output = Result<R::Result>> + 'static,
>( >(
&mut self, &mut self,
handler: fn(R::Params, Rc<Context>) -> Fut, handler: fn(R::Params, Rc<Context>) -> Fut,
@ -386,7 +384,7 @@ pub fn register_request_handlers(rh: &mut RequestHandler) {
} }
#[cfg(feature = "preview")] #[cfg(feature = "preview")]
pub fn show_preview_command(params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<(), Error> { pub fn show_preview_command(params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<()> {
let document_cache = &mut ctx.document_cache.borrow_mut(); let document_cache = &mut ctx.document_cache.borrow_mut();
let config = &document_cache.documents.compiler_config; let config = &document_cache.documents.compiler_config;
@ -415,7 +413,7 @@ pub fn show_preview_command(params: &[serde_json::Value], ctx: &Rc<Context>) ->
} }
#[cfg(feature = "preview")] #[cfg(feature = "preview")]
pub fn set_design_mode(params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<(), Error> { pub fn set_design_mode(params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<()> {
let e = || "InvalidParameter"; let e = || "InvalidParameter";
let enable = if let serde_json::Value::Bool(b) = params.get(0).ok_or_else(e)? { let enable = if let serde_json::Value::Bool(b) = params.get(0).ok_or_else(e)? {
b b
@ -428,7 +426,7 @@ pub fn set_design_mode(params: &[serde_json::Value], ctx: &Rc<Context>) -> Resul
} }
#[cfg(feature = "preview")] #[cfg(feature = "preview")]
pub fn toggle_design_mode(_params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<(), Error> { pub fn toggle_design_mode(_params: &[serde_json::Value], ctx: &Rc<Context>) -> Result<()> {
ctx.preview.set_design_mode(!ctx.preview.design_mode()); ctx.preview.set_design_mode(!ctx.preview.design_mode());
Ok(()) Ok(())
} }
@ -436,7 +434,7 @@ pub fn toggle_design_mode(_params: &[serde_json::Value], ctx: &Rc<Context>) -> R
pub fn query_properties_command( pub fn query_properties_command(
params: &[serde_json::Value], params: &[serde_json::Value],
ctx: &Rc<Context>, ctx: &Rc<Context>,
) -> Result<serde_json::Value, Error> { ) -> Result<serde_json::Value> {
let document_cache = &mut ctx.document_cache.borrow_mut(); let document_cache = &mut ctx.document_cache.borrow_mut();
let text_document_uri = serde_json::from_value::<lsp_types::TextDocumentIdentifier>( let text_document_uri = serde_json::from_value::<lsp_types::TextDocumentIdentifier>(
@ -472,7 +470,7 @@ pub fn query_properties_command(
pub async fn set_binding_command( pub async fn set_binding_command(
params: &[serde_json::Value], params: &[serde_json::Value],
ctx: &Rc<Context>, ctx: &Rc<Context>,
) -> Result<serde_json::Value, Error> { ) -> Result<serde_json::Value> {
let text_document = serde_json::from_value::<lsp_types::OptionalVersionedTextDocumentIdentifier>( let text_document = serde_json::from_value::<lsp_types::OptionalVersionedTextDocumentIdentifier>(
params.get(0).ok_or("No text document provided")?.clone(), params.get(0).ok_or("No text document provided")?.clone(),
)?; )?;
@ -563,7 +561,7 @@ pub async fn set_binding_command(
pub async fn remove_binding_command( pub async fn remove_binding_command(
params: &[serde_json::Value], params: &[serde_json::Value],
ctx: &Rc<Context>, ctx: &Rc<Context>,
) -> Result<serde_json::Value, Error> { ) -> Result<serde_json::Value> {
let text_document = serde_json::from_value::<lsp_types::OptionalVersionedTextDocumentIdentifier>( let text_document = serde_json::from_value::<lsp_types::OptionalVersionedTextDocumentIdentifier>(
params.get(0).ok_or("No text document provided")?.clone(), params.get(0).ok_or("No text document provided")?.clone(),
)?; )?;
@ -692,7 +690,7 @@ pub async fn reload_document(
uri: lsp_types::Url, uri: lsp_types::Url,
version: i32, version: i32,
document_cache: &mut DocumentCache, document_cache: &mut DocumentCache,
) -> Result<(), Error> { ) -> Result<()> {
let lsp_diags = reload_document_impl(Some(ctx), content, uri, version, document_cache).await; let lsp_diags = reload_document_impl(Some(ctx), content, uri, version, document_cache).await;
for (uri, diagnostics) in lsp_diags { for (uri, diagnostics) in lsp_diags {
@ -1053,7 +1051,7 @@ fn find_element_id_for_highlight(
None None
} }
pub async fn load_configuration(ctx: &Context) -> Result<(), Error> { pub async fn load_configuration(ctx: &Context) -> Result<()> {
if !ctx if !ctx
.init_param .init_param
.capabilities .capabilities

View file

@ -2,11 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
use super::DocumentCache; use super::DocumentCache;
use crate::common::{Error, Result};
use crate::util::{ use crate::util::{
map_node, map_node_and_url, map_position, map_range, to_lsp_diag, with_property_lookup_ctx, map_node, map_node_and_url, map_position, map_range, to_lsp_diag, with_property_lookup_ctx,
ExpressionContextInfo, ExpressionContextInfo,
}; };
use crate::Error;
use i_slint_compiler::diagnostics::{BuildDiagnostics, Spanned}; use i_slint_compiler::diagnostics::{BuildDiagnostics, Spanned};
use i_slint_compiler::langtype::{ElementType, Type}; use i_slint_compiler::langtype::{ElementType, Type};
@ -410,7 +410,7 @@ pub(crate) fn query_properties(
uri: &lsp_types::Url, uri: &lsp_types::Url,
source_version: i32, source_version: i32,
element: &ElementRc, element: &ElementRc,
) -> Result<QueryPropertyResponse, crate::Error> { ) -> Result<QueryPropertyResponse> {
Ok(QueryPropertyResponse { Ok(QueryPropertyResponse {
properties: get_properties(element), properties: get_properties(element),
element: Some(get_element_information(element)), element: Some(get_element_information(element)),
@ -422,7 +422,7 @@ pub(crate) fn query_properties(
fn get_property_information( fn get_property_information(
properties: &[PropertyInformation], properties: &[PropertyInformation],
property_name: &str, property_name: &str,
) -> Result<PropertyInformation, Error> { ) -> Result<PropertyInformation> {
if let Some(property) = properties.iter().find(|pi| pi.name == property_name) { if let Some(property) = properties.iter().find(|pi| pi.name == property_name) {
Ok(property.clone()) Ok(property.clone())
} else { } else {
@ -482,7 +482,7 @@ fn set_binding_on_existing_property(
property: &PropertyInformation, property: &PropertyInformation,
new_expression: String, new_expression: String,
diag: &mut BuildDiagnostics, diag: &mut BuildDiagnostics,
) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>), Error> { ) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>)> {
let workspace_edit = (!diag.has_error()) let workspace_edit = (!diag.has_error())
.then(|| { .then(|| {
create_workspace_edit_for_set_binding_on_existing_property( create_workspace_edit_for_set_binding_on_existing_property(
@ -599,7 +599,7 @@ fn set_binding_on_known_property(
property_name: &str, property_name: &str,
new_expression: &str, new_expression: &str,
diag: &mut BuildDiagnostics, diag: &mut BuildDiagnostics,
) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>), Error> { ) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>)> {
let workspace_edit = (!diag.has_error()) let workspace_edit = (!diag.has_error())
.then(|| { .then(|| {
create_workspace_edit_for_set_binding_on_known_property( create_workspace_edit_for_set_binding_on_known_property(
@ -643,7 +643,7 @@ pub(crate) fn set_binding(
element: &ElementRc, element: &ElementRc,
property_name: &str, property_name: &str,
new_expression: String, new_expression: String,
) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>), Error> { ) -> Result<(SetBindingResponse, Option<lsp_types::WorkspaceEdit>)> {
let (mut diag, expression_node) = { let (mut diag, expression_node) = {
let mut diagnostics = BuildDiagnostics::default(); let mut diagnostics = BuildDiagnostics::default();
@ -737,7 +737,7 @@ pub(crate) fn remove_binding(
uri: &lsp_types::Url, uri: &lsp_types::Url,
element: &ElementRc, element: &ElementRc,
property_name: &str, property_name: &str,
) -> Result<lsp_types::WorkspaceEdit, Error> { ) -> Result<lsp_types::WorkspaceEdit> {
let element = element.borrow(); let element = element.borrow();
let source_file = element.node.as_ref().and_then(|n| n.source_file()); let source_file = element.node.as_ref().and_then(|n| n.source_file());

View file

@ -10,7 +10,7 @@ pub mod lsp_ext;
mod preview; mod preview;
pub mod util; pub mod util;
use common::PreviewApi; use common::{PreviewApi, Result};
use language::*; use language::*;
use i_slint_compiler::CompilerConfiguration; use i_slint_compiler::CompilerConfiguration;
@ -67,11 +67,7 @@ impl PreviewApi for Previewer {
preview::config_changed(_style, _include_paths); preview::config_changed(_style, _include_paths);
} }
fn highlight( fn highlight(&self, _path: Option<std::path::PathBuf>, _offset: u32) -> Result<()> {
&self,
_path: Option<std::path::PathBuf>,
_offset: u32,
) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "preview")] #[cfg(feature = "preview")]
preview::highlight(_path, _offset); preview::highlight(_path, _offset);
Ok(()) Ok(())
@ -111,11 +107,7 @@ type OutgoingRequestQueue = Arc<Mutex<HashMap<RequestId, OutgoingRequest>>>;
#[derive(Clone)] #[derive(Clone)]
pub struct ServerNotifier(crossbeam_channel::Sender<Message>, OutgoingRequestQueue); pub struct ServerNotifier(crossbeam_channel::Sender<Message>, OutgoingRequestQueue);
impl ServerNotifier { impl ServerNotifier {
pub fn send_notification( pub fn send_notification(&self, method: String, params: impl serde::Serialize) -> Result<()> {
&self,
method: String,
params: impl serde::Serialize,
) -> Result<(), Error> {
self.0.send(Message::Notification(lsp_server::Notification::new(method, params)))?; self.0.send(Message::Notification(lsp_server::Notification::new(method, params)))?;
Ok(()) Ok(())
} }
@ -123,7 +115,7 @@ impl ServerNotifier {
pub fn send_request<T: lsp_types::request::Request>( pub fn send_request<T: lsp_types::request::Request>(
&self, &self,
request: T::Params, request: T::Params,
) -> Result<impl Future<Output = Result<T::Result, Error>>, Error> { ) -> Result<impl Future<Output = Result<T::Result>>> {
static REQ_ID: atomic::AtomicI32 = atomic::AtomicI32::new(0); static REQ_ID: atomic::AtomicI32 = atomic::AtomicI32::new(0);
let id = RequestId::from(REQ_ID.fetch_add(1, atomic::Ordering::Relaxed)); let id = RequestId::from(REQ_ID.fetch_add(1, atomic::Ordering::Relaxed));
let msg = let msg =
@ -153,11 +145,7 @@ impl ServerNotifier {
} }
impl RequestHandler { impl RequestHandler {
async fn handle_request( async fn handle_request(&self, request: lsp_server::Request, ctx: &Rc<Context>) -> Result<()> {
&self,
request: lsp_server::Request,
ctx: &Rc<Context>,
) -> Result<(), Error> {
if let Some(x) = self.0.get(&request.method.as_str()) { if let Some(x) = self.0.get(&request.method.as_str()) {
match x(request.params, ctx.clone()).await { match x(request.params, ctx.clone()).await {
Ok(r) => ctx Ok(r) => ctx
@ -219,7 +207,7 @@ fn main() {
} }
} }
pub fn run_lsp_server() -> Result<(), Error> { pub fn run_lsp_server() -> Result<()> {
let (connection, io_threads) = Connection::stdio(); let (connection, io_threads) = Connection::stdio();
let (id, params) = connection.initialize_start()?; let (id, params) = connection.initialize_start()?;
@ -233,7 +221,7 @@ pub fn run_lsp_server() -> Result<(), Error> {
Ok(()) Ok(())
} }
fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<(), Error> { fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()> {
let mut compiler_config = let mut compiler_config =
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter); CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
@ -254,7 +242,7 @@ fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<(),
preview: Box::new(Previewer { server_notifier }), preview: Box::new(Previewer { server_notifier }),
}); });
let mut futures = Vec::<Pin<Box<dyn Future<Output = Result<(), Error>>>>>::new(); let mut futures = Vec::<Pin<Box<dyn Future<Output = Result<()>>>>>::new();
let mut first_future = Box::pin(load_configuration(&ctx)); let mut first_future = Box::pin(load_configuration(&ctx));
// We are waiting in this loop for two kind of futures: // We are waiting in this loop for two kind of futures:
@ -317,10 +305,7 @@ fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<(),
Ok(()) Ok(())
} }
async fn handle_notification( async fn handle_notification(req: lsp_server::Notification, ctx: &Rc<Context>) -> Result<()> {
req: lsp_server::Notification,
ctx: &Rc<Context>,
) -> Result<(), Error> {
match &*req.method { match &*req.method {
DidOpenTextDocument::METHOD => { DidOpenTextDocument::METHOD => {
let params: DidOpenTextDocumentParams = serde_json::from_value(req.params)?; let params: DidOpenTextDocumentParams = serde_json::from_value(req.params)?;

View file

@ -11,9 +11,10 @@ mod preview;
pub mod util; pub mod util;
use common::PreviewApi; use common::PreviewApi;
use common::{Error, Result};
use i_slint_compiler::CompilerConfiguration; use i_slint_compiler::CompilerConfiguration;
use js_sys::Function; use js_sys::Function;
pub use language::{Context, DocumentCache, Error, RequestHandler}; pub use language::{Context, DocumentCache, RequestHandler};
use serde::Serialize; use serde::Serialize;
use std::cell::RefCell; use std::cell::RefCell;
use std::future::Future; use std::future::Future;
@ -22,6 +23,8 @@ use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
type JsResult<T> = std::result::Result<T, JsError>;
pub mod wasm_prelude { pub mod wasm_prelude {
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -70,14 +73,10 @@ impl PreviewApi for Previewer {
// do nothing! // do nothing!
} }
fn highlight( fn highlight(&self, path: Option<std::path::PathBuf>, offset: u32) -> Result<()> {
&self,
path: Option<std::path::PathBuf>,
offset: u32,
) -> Result<(), Box<dyn std::error::Error>> {
self.highlight_in_preview self.highlight_in_preview
.call2(&JsValue::UNDEFINED, &to_value(&path.unwrap_or_default())?, &offset.into()) .call2(&JsValue::UNDEFINED, &to_value(&path.unwrap_or_default())?, &offset.into())
.map_err(|x| std::io::Error::new(ErrorKind::Other, format!("{x:?}")))?; .map_err(|x| format!("{x:?}"))?;
Ok(()) Ok(())
} }
} }
@ -88,7 +87,7 @@ pub struct ServerNotifier {
send_request: Function, send_request: Function,
} }
impl ServerNotifier { impl ServerNotifier {
pub fn send_notification(&self, method: String, params: impl Serialize) -> Result<(), Error> { pub fn send_notification(&self, method: String, params: impl Serialize) -> Result<()> {
self.send_notification self.send_notification
.call2(&JsValue::UNDEFINED, &method.into(), &to_value(&params)?) .call2(&JsValue::UNDEFINED, &method.into(), &to_value(&params)?)
.map_err(|x| format!("Error calling send_notification: {x:?}"))?; .map_err(|x| format!("Error calling send_notification: {x:?}"))?;
@ -98,7 +97,7 @@ impl ServerNotifier {
pub fn send_request<T: lsp_types::request::Request>( pub fn send_request<T: lsp_types::request::Request>(
&self, &self,
request: T::Params, request: T::Params,
) -> Result<impl Future<Output = Result<T::Result, Error>>, Error> { ) -> Result<impl Future<Output = Result<T::Result>>> {
let promise = self let promise = self
.send_request .send_request
.call2(&JsValue::UNDEFINED, &T::METHOD.into(), &to_value(&request)?) .call2(&JsValue::UNDEFINED, &T::METHOD.into(), &to_value(&request)?)
@ -118,7 +117,7 @@ impl RequestHandler {
method: String, method: String,
params: JsValue, params: JsValue,
ctx: Rc<Context>, ctx: Rc<Context>,
) -> Result<JsValue, Error> { ) -> Result<JsValue> {
if let Some(f) = self.0.get(&method.as_str()) { if let Some(f) = self.0.get(&method.as_str()) {
let param = serde_wasm_bindgen::from_value(params) let param = serde_wasm_bindgen::from_value(params)
.map_err(|x| format!("invalid param to handle_request: {x:?}"))?; .map_err(|x| format!("invalid param to handle_request: {x:?}"))?;
@ -207,7 +206,7 @@ pub fn create(
send_request: SendRequestFunction, send_request: SendRequestFunction,
load_file: ImportCallbackFunction, load_file: ImportCallbackFunction,
highlight_in_preview: HighlightInPreviewFunction, highlight_in_preview: HighlightInPreviewFunction,
) -> Result<SlintServer, JsError> { ) -> JsResult<SlintServer> {
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
let init_param = serde_wasm_bindgen::from_value(init_param)?; let init_param = serde_wasm_bindgen::from_value(init_param)?;
@ -242,7 +241,7 @@ pub fn create(
#[wasm_bindgen] #[wasm_bindgen]
impl SlintServer { impl SlintServer {
#[wasm_bindgen] #[wasm_bindgen]
pub fn server_initialize_result(&self, cap: JsValue) -> Result<JsValue, JsError> { pub fn server_initialize_result(&self, cap: JsValue) -> JsResult<JsValue> {
Ok(to_value(&language::server_initialize_result(&serde_wasm_bindgen::from_value(cap)?))?) Ok(to_value(&language::server_initialize_result(&serde_wasm_bindgen::from_value(cap)?))?)
} }
@ -267,7 +266,7 @@ impl SlintServer {
} }
/* #[wasm_bindgen] /* #[wasm_bindgen]
pub fn show_preview(&self, params: JsValue) -> Result<(), JsError> { pub fn show_preview(&self, params: JsValue) -> JsResult<()> {
language::show_preview_command( language::show_preview_command(
&serde_wasm_bindgen::from_value(params)?, &serde_wasm_bindgen::from_value(params)?,
&ServerNotifier, &ServerNotifier,
@ -289,7 +288,7 @@ impl SlintServer {
} }
#[wasm_bindgen] #[wasm_bindgen]
pub async fn reload_config(&self) -> Result<(), JsError> { pub async fn reload_config(&self) -> JsResult<()> {
let guard = self.reentry_guard.clone(); let guard = self.reentry_guard.clone();
let _lock = ReentryGuard::lock(guard).await; let _lock = ReentryGuard::lock(guard).await;
language::load_configuration(&self.ctx).await.map_err(|e| JsError::new(&e.to_string())) language::load_configuration(&self.ctx).await.map_err(|e| JsError::new(&e.to_string()))
@ -309,6 +308,6 @@ async fn load_file(path: String, load_file: &Function) -> std::io::Result<String
// Use a JSON friendly representation to avoid using ES maps instead of JS objects. // Use a JSON friendly representation to avoid using ES maps instead of JS objects.
fn to_value<T: serde::Serialize + ?Sized>( fn to_value<T: serde::Serialize + ?Sized>(
value: &T, value: &T,
) -> Result<wasm_bindgen::JsValue, serde_wasm_bindgen::Error> { ) -> std::result::Result<wasm_bindgen::JsValue, serde_wasm_bindgen::Error> {
value.serialize(&serde_wasm_bindgen::Serializer::json_compatible()) value.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
} }