diff --git a/Cargo.lock b/Cargo.lock index 76bf04dc899..c707783fd78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1966,9 +1966,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.92.0" +version = "0.92.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a69d4142d51b208c9fc3cea68b1a7fcef30354e7aa6ccad07250fd8430fc76" +checksum = "c79d4897790e8fd2550afa6d6125821edb5716e60e0e285046e070f0f6a06e0e" dependencies = [ "bitflags", "serde", diff --git a/forc/src/cli/commands/lsp.rs b/forc/src/cli/commands/lsp.rs index d6e977edaa2..9e73ffccf83 100644 --- a/forc/src/cli/commands/lsp.rs +++ b/forc/src/cli/commands/lsp.rs @@ -1,11 +1,19 @@ -use anyhow::Result; +use crate::ops::forc_lsp; +use anyhow::{bail, Result}; use clap::Parser; /// Run the LSP server. #[derive(Debug, Parser)] -pub(crate) struct Command {} +pub struct Command { + /// Instructs the client to draw squiggly lines + /// under all of the tokens that our server managed to parse + #[clap(long)] + pub parsed_tokens_as_warnings: bool, +} -pub(crate) async fn exec(_command: Command) -> Result<()> { - sway_lsp::start().await; - Ok(()) +pub(crate) async fn exec(command: Command) -> Result<()> { + match forc_lsp::exec(command).await { + Err(e) => bail!(e), + _ => Ok(()), + } } diff --git a/forc/src/cli/mod.rs b/forc/src/cli/mod.rs index a5c7ec84e92..7b13aa5e26f 100644 --- a/forc/src/cli/mod.rs +++ b/forc/src/cli/mod.rs @@ -16,7 +16,7 @@ pub use explorer::Command as ExplorerCommand; pub use format::Command as FormatCommand; pub use init::Command as InitCommand; pub use json_abi::Command as JsonAbiCommand; -use lsp::Command as LspCommand; +pub use lsp::Command as LspCommand; use parse_bytecode::Command as ParseBytecodeCommand; pub use run::Command as RunCommand; use test::Command as TestCommand; diff --git a/forc/src/ops/forc_lsp.rs b/forc/src/ops/forc_lsp.rs new file mode 100644 index 00000000000..7ca1630bfe0 --- /dev/null +++ b/forc/src/ops/forc_lsp.rs @@ -0,0 +1,13 @@ +use crate::cli::LspCommand; +use anyhow::Result; +use sway_lsp::utils::debug; + +pub async fn exec(command: LspCommand) -> Result<()> { + let config = debug::DebugFlags { + parsed_tokens_as_warnings: command.parsed_tokens_as_warnings, + }; + + sway_lsp::start(config).await; + + Ok(()) +} diff --git a/forc/src/ops/mod.rs b/forc/src/ops/mod.rs index c6df7a4120c..e099ca70597 100644 --- a/forc/src/ops/mod.rs +++ b/forc/src/ops/mod.rs @@ -5,5 +5,6 @@ pub mod forc_deploy; pub mod forc_explorer; pub mod forc_fmt; pub mod forc_init; +pub mod forc_lsp; pub mod forc_run; pub mod forc_update; diff --git a/sway-lsp/src/lib.rs b/sway-lsp/src/lib.rs index 55e99d62622..c612aa8f059 100644 --- a/sway-lsp/src/lib.rs +++ b/sway-lsp/src/lib.rs @@ -4,13 +4,14 @@ mod capabilities; mod core; mod server; mod sway_config; -mod utils; +pub mod utils; use server::Backend; +use utils::debug::DebugFlags; -pub async fn start() { +pub async fn start(config: DebugFlags) { let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); - let (service, socket) = LspService::new(Backend::new); + let (service, socket) = LspService::new(|client| Backend::new(client, config)); Server::new(stdin, stdout, socket).serve(service).await; } diff --git a/sway-lsp/src/server.rs b/sway-lsp/src/server.rs index 1732d7b42e1..ada4055ab92 100644 --- a/sway-lsp/src/server.rs +++ b/sway-lsp/src/server.rs @@ -3,6 +3,7 @@ use crate::core::{ document::{DocumentError, TextDocument}, session::Session, }; +use crate::utils::debug::{self, DebugFlags}; use forc_util::find_manifest_dir; use std::sync::Arc; use sway_utils::helpers::get_sway_files; @@ -13,12 +14,17 @@ use tower_lsp::{jsonrpc, Client, LanguageServer}; pub struct Backend { pub client: Client, session: Arc, + config: DebugFlags, } impl Backend { - pub fn new(client: Client) -> Self { + pub fn new(client: Client, config: DebugFlags) -> Self { let session = Arc::new(Session::new()); - Backend { client, session } + Backend { + client, + session, + config, + } } async fn log_info_message(&self, message: &str) { @@ -110,11 +116,22 @@ impl LanguageServer for Backend { // Document Handlers async fn did_open(&self, params: DidOpenTextDocumentParams) { + let uri = params.text_document.uri.clone(); let diagnostics = capabilities::text_sync::handle_open_file(self.session.clone(), ¶ms); - if !diagnostics.is_empty() { + // If parsed_tokens_as_warnings is true, take over the normal error and warning display behavior + // and instead show the parsed tokens as warnings. + // This is useful for debugging the lsp parser. + if self.config.parsed_tokens_as_warnings { + if let Some(document) = self.session.documents.get(uri.path()) { + let diagnostics = debug::generate_warnings_for_parsed_tokens(document.get_tokens()); + self.client + .publish_diagnostics(uri, diagnostics, None) + .await; + } + } else if !diagnostics.is_empty() { self.client - .publish_diagnostics(params.text_document.uri, diagnostics, None) + .publish_diagnostics(uri, diagnostics, None) .await; } } @@ -337,9 +354,13 @@ fn main() { assert_eq!(response, Ok(None)); } + fn config() -> DebugFlags { + Default::default() + } + #[tokio::test] async fn initialize() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -347,7 +368,7 @@ fn main() { #[tokio::test] async fn initialized() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -358,7 +379,7 @@ fn main() { #[tokio::test] async fn initializes_only_once() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let initialize = initialize_request(&mut service).await; @@ -374,7 +395,7 @@ fn main() { #[tokio::test] async fn shutdown() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -396,7 +417,7 @@ fn main() { #[tokio::test] async fn refuses_requests_after_shutdown() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -411,7 +432,7 @@ fn main() { #[tokio::test] async fn did_open() { - let (mut service, mut messages) = LspService::new(Backend::new); + let (mut service, mut messages) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -436,7 +457,7 @@ fn main() { #[tokio::test] async fn did_close() { - let (mut service, _) = LspService::new(Backend::new); + let (mut service, _) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; @@ -461,7 +482,7 @@ fn main() { #[tokio::test] async fn did_change() { - let (mut service, mut messages) = LspService::new(Backend::new); + let (mut service, mut messages) = LspService::new(|client| Backend::new(client, config())); // send "initialize" request let _ = initialize_request(&mut service).await; diff --git a/sway-lsp/src/utils/debug.rs b/sway-lsp/src/utils/debug.rs new file mode 100644 index 00000000000..8a70c96786e --- /dev/null +++ b/sway-lsp/src/utils/debug.rs @@ -0,0 +1,24 @@ +use crate::core::token::Token; +use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity}; + +// Flags for debugging various parts of the server +#[derive(Debug, Default)] +pub struct DebugFlags { + /// Instructs the client to draw squiggly lines + /// under all of the tokens that our server managed to parse + pub parsed_tokens_as_warnings: bool, +} + +pub fn generate_warnings_for_parsed_tokens(tokens: &[Token]) -> Vec { + let warnings = tokens + .iter() + .map(|token| Diagnostic { + range: token.range, + severity: Some(DiagnosticSeverity::WARNING), + message: token.name.clone(), + ..Default::default() + }) + .collect(); + + warnings +} diff --git a/sway-lsp/src/utils/mod.rs b/sway-lsp/src/utils/mod.rs index d07d6ffecff..4af74a1cc0f 100644 --- a/sway-lsp/src/utils/mod.rs +++ b/sway-lsp/src/utils/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod common; +pub mod debug; pub(crate) mod function;