diff --git a/components/clarity-lsp/src/common/backend.rs b/components/clarity-lsp/src/common/backend.rs index 20d5293b6..d8c3cb461 100644 --- a/components/clarity-lsp/src/common/backend.rs +++ b/components/clarity-lsp/src/common/backend.rs @@ -5,9 +5,9 @@ use clarinet_files::{FileAccessor, FileLocation, ProjectManifest}; use clarity_repl::clarity::diagnostic::Diagnostic; use clarity_repl::repl::ContractDeployer; use lsp_types::{ - CompletionItem, CompletionParams, DocumentSymbol, DocumentSymbolParams, GotoDefinitionParams, - Hover, HoverParams, InitializeParams, InitializeResult, Location, SignatureHelp, - SignatureHelpParams, + CompletionItem, CompletionParams, DocumentFormattingParams, DocumentSymbol, + DocumentSymbolParams, GotoDefinitionParams, Hover, HoverParams, InitializeParams, + InitializeResult, Location, SignatureHelp, SignatureHelpParams, TextEdit, }; use serde::{Deserialize, Serialize}; use std::sync::{Arc, RwLock}; @@ -258,6 +258,7 @@ pub enum LspRequest { Definition(GotoDefinitionParams), Hover(HoverParams), DocumentSymbol(DocumentSymbolParams), + DocumentFormatting(DocumentFormattingParams), Initialize(Box), } @@ -266,8 +267,9 @@ pub enum LspRequestResponse { CompletionItems(Vec), SignatureHelp(Option), Definition(Option), - DocumentSymbol(Vec), Hover(Option), + DocumentSymbol(Vec), + DocumentFormatting(Option>), Initialize(Box), } @@ -343,6 +345,28 @@ pub fn process_request( Ok(LspRequestResponse::DocumentSymbol(document_symbols)) } + LspRequest::DocumentFormatting(param) => { + let file_url = param.text_document.uri; + let contract_location = match get_contract_location(&file_url) { + Some(contract_location) => contract_location, + None => return Ok(LspRequestResponse::DocumentFormatting(None)), + }; + + // todo: handling formatting options, should reconciliate `param.options` and `editor_state.settings.` + // i saw that formatting_options accepts arbitrary custom props `[key: string]: boolean | integer | string;` + let formatted_file = editor_state + .try_read(|es| es.format_contract(&contract_location)) + .unwrap_or_default(); + println!("file formatted!"); + + match formatted_file { + Some(formatted_file) => Ok(LspRequestResponse::DocumentFormatting(Some(vec![ + formatted_file, + ]))), + None => Ok(LspRequestResponse::DocumentFormatting(None)), + } + } + LspRequest::Hover(params) => { let file_url = params.text_document_position_params.text_document.uri; let contract_location = match get_contract_location(&file_url) { @@ -355,6 +379,7 @@ pub fn process_request( .unwrap_or_default(); Ok(LspRequestResponse::Hover(hover_data)) } + _ => Err(format!("Unexpected command: {:?}", &command)), } } diff --git a/components/clarity-lsp/src/common/requests/capabilities.rs b/components/clarity-lsp/src/common/requests/capabilities.rs index f04e32bb8..99c696753 100644 --- a/components/clarity-lsp/src/common/requests/capabilities.rs +++ b/components/clarity-lsp/src/common/requests/capabilities.rs @@ -66,6 +66,7 @@ pub fn get_capabilities(initialization_options: &InitializationOptions) -> Serve }), false => None, }, + document_formatting_provider: Some(lsp_types::OneOf::Left(true)), ..ServerCapabilities::default() } } diff --git a/components/clarity-lsp/src/common/state.rs b/components/clarity-lsp/src/common/state.rs index f626719ba..49e988d44 100644 --- a/components/clarity-lsp/src/common/state.rs +++ b/components/clarity-lsp/src/common/state.rs @@ -43,7 +43,7 @@ pub struct ActiveContractData { pub expressions: Option>, pub definitions: Option>, pub diagnostic: Option, - source: String, + pub source: String, } impl ActiveContractData { @@ -349,6 +349,31 @@ impl EditorState { ast_symbols.get_symbols(expressions) } + pub fn format_contract(&self, contract_location: &FileLocation) -> Option { + let active_contract = self.active_contracts.get(contract_location)?; + let source = &active_contract.source; + + // call requests/formmatter.rs format_contract + let formatted = source.clone(); + + // start with a format all document strategy + let range = lsp_types::Range { + start: lsp_types::Position { + line: 0, + character: 0, + }, + end: lsp_types::Position { + line: formatted.lines().count() as u32, + character: 0, + }, + }; + + Some(lsp_types::TextEdit { + range, + new_text: formatted, + }) + } + pub fn get_definition_location( &self, contract_location: &FileLocation, diff --git a/components/clarity-lsp/src/vscode_bridge.rs b/components/clarity-lsp/src/vscode_bridge.rs index 0b261e053..08084a32b 100644 --- a/components/clarity-lsp/src/vscode_bridge.rs +++ b/components/clarity-lsp/src/vscode_bridge.rs @@ -12,8 +12,8 @@ use lsp_types::notification::{ Initialized, Notification, }; use lsp_types::request::{ - Completion, DocumentSymbolRequest, GotoDefinition, HoverRequest, Initialize, Request, - SignatureHelpRequest, + Completion, DocumentSymbolRequest, Formatting, GotoDefinition, HoverRequest, Initialize, + Request, SignatureHelpRequest, }; use lsp_types::{ DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, @@ -26,7 +26,6 @@ use std::sync::{Arc, RwLock}; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::future_to_promise; -#[cfg(debug_assertions)] use crate::utils::log; #[wasm_bindgen] @@ -249,6 +248,17 @@ impl LspVscodeBridge { } } + Formatting::METHOD => { + let lsp_response = process_request( + LspRequest::DocumentFormatting(decode_from_js(js_params)?), + &EditorStateInput::RwLock(self.editor_state_lock.clone()), + ); + if let Ok(LspRequestResponse::DocumentFormatting(response)) = lsp_response { + log!("formatting response: {:?}", response); + return response.serialize(&serializer).map_err(|_| JsValue::NULL); + } + } + HoverRequest::METHOD => { let lsp_response = process_request( LspRequest::Hover(decode_from_js(js_params)?), @@ -260,7 +270,6 @@ impl LspVscodeBridge { } _ => { - #[cfg(debug_assertions)] log!("unexpected request ({})", method); } }; diff --git a/components/clarity-vscode/server/src/serverBrowser.ts b/components/clarity-vscode/server/src/serverBrowser.ts index ca23e27a5..ecb564510 100644 --- a/components/clarity-vscode/server/src/serverBrowser.ts +++ b/components/clarity-vscode/server/src/serverBrowser.ts @@ -23,7 +23,7 @@ declare const __EXTENSION_URL__: string; new BrowserMessageWriter(self), ); - initSync(await wasmModule); + initSync({ module: await wasmModule }); const bridge = new LspVscodeBridge( connection.sendDiagnostics, diff --git a/components/clarity-vscode/web-extension.code-workspace b/components/clarity-vscode/web-extension.code-workspace index f9b7f7c34..83ee7f606 100644 --- a/components/clarity-vscode/web-extension.code-workspace +++ b/components/clarity-vscode/web-extension.code-workspace @@ -1,22 +1,24 @@ { "folders": [ { - "path": "./" + "path": "./", }, { - "path": "../../" - } + "path": "../../", + }, ], "settings": { "rust-analyzer.cargo.noDefaultFeatures": true, "rust-analyzer.cargo.features": ["clarity-lsp/wasm"], + "rust-analyzer.cargo.allTargets": false, + "rust-analyzer.check.workspace": false, "rust-analyzer.check.overrideCommand": [ "cargo", "clippy", "--no-default-features", "--package=clarity-lsp", "--features=wasm", - "--message-format=json" - ] - } + "--message-format=json", + ], + }, }