feat(vscode): watch configuration file
MODIFY
crates/rome_fs/src/lib.rs
crates/rome_fs/src/lib.rs
@@ -4,7 +4,7 @@ mod path;
pub use fs::{
ErrorEntry, FileSystem, FileSystemExt, MemoryFileSystem, OpenOptions, OsFileSystem,
- TraversalContext, TraversalScope,
+ TraversalContext, TraversalScope, CONFIG_NAME,
};
pub use interner::{AtomicInterner, IndexSetInterner, PathInterner};
pub use path::RomePath;

MODIFY
crates/rome_lsp/src/handlers/formatting.rs
crates/rome_lsp/src/handlers/formatting.rs
@@ -7,9 +7,9 @@ use rome_service::{
RomeError,
};
use tower_lsp::lsp_types::*;
-use tracing::trace;
+use tracing::debug;
-#[tracing::instrument(level = "trace", skip(session), err)]
+#[tracing::instrument(level = "debug", skip(session), err)]
pub(crate) fn format(
session: &Session,
params: DocumentFormattingParams,
@@ -19,7 +19,7 @@ pub(crate) fn format(
let doc = session.document(&url)?;
- trace!("Formatting...");
+ debug!("Formatting...");
let result = session
.workspace
.format_file(FormatFileParams { path: rome_path });

MODIFY
crates/rome_lsp/src/server.rs
crates/rome_lsp/src/server.rs
-use std::collections::HashMap;
-use std::sync::atomic::{AtomicU64, Ordering};
-use std::sync::{Arc, Mutex};
-
use crate::capabilities::server_capabilities;
use crate::requests::syntax_tree::{SyntaxTreePayload, SYNTAX_TREE_REQUEST};
use crate::session::{ClientInformation, Session, SessionHandle, SessionKey};
@@ -10,8 +6,12 @@ use crate::{handlers, requests};
use futures::future::ready;
use futures::FutureExt;
use rome_console::markup;
+use rome_fs::CONFIG_NAME;
use rome_service::workspace::{RageEntry, RageParams, RageResult};
use rome_service::{workspace, Workspace};
+use std::collections::HashMap;
+use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{Arc, Mutex};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::sync::Notify;
use tokio::task::spawn_blocking;
@@ -133,6 +133,23 @@ impl LSPServer {
.await;
}
+ let base_path = self.session.base_path();
+
+ if let Some(base_path) = base_path {
+ let registration_options = DidChangeWatchedFilesRegistrationOptions {
+ watchers: vec![FileSystemWatcher {
+ glob_pattern: format!("{}/rome.json", base_path.display()),
+ kind: Some(WatchKind::all()),
+ }],
+ };
+ self.register_capability(Registration {
+ id: "workspace/didChangeWatchedFiles".to_string(),
+ method: "workspace/didChangeWatchedFiles".to_string(),
+ register_options: Some(serde_json::to_value(registration_options).unwrap()),
+ })
+ .await;
+ }
+
if rename {
self.register_capability(Registration {
id: "textDocument/rename".to_string(),
@@ -217,6 +234,37 @@ impl LanguageServer for LSPServer {
self.setup_capabilities().await;
}
+ #[tracing::instrument(level = "trace", skip(self))]
+ async fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) {
+ let file_paths = params
+ .changes
+ .iter()
+ .map(|change| change.uri.to_file_path());
+ for file_path in file_paths {
+ match file_path {
+ Ok(file_path) => {
+ let base_path = self.session.base_path();
+ if let Some(base_path) = base_path {
+ let possible_rome_json = file_path.strip_prefix(&base_path);
+ if let Ok(possible_rome_json) = possible_rome_json {
+ if possible_rome_json.display().to_string() == CONFIG_NAME {
+ self.session.update_configuration().await;
+ self.session.fetch_client_configuration().await;
+ // for now we are only interested to the configuration file,
+ // so it's OK to exist the loop
+ break;
+ }
+ }
+ }
+ }
+ Err(_) => {
+ error!("The Workspace root URI {file_path:?} could not be parsed as a filesystem path");
+ continue;
+ }
+ }
+ }
+ }
+
async fn did_open(&self, params: DidOpenTextDocumentParams) {
handlers::text_document::did_open(&self.session, params)
.await
@@ -367,7 +415,7 @@ impl ServerFactory {
// "shutdown" is not part of the Workspace API
builder = builder.custom_method("rome/shutdown", |server: &LSPServer, (): ()| {
- tracing::info!("Sending shutdown signal");
+ info!("Sending shutdown signal");
server.session.broadcast_shutdown();
ready(Ok(Some(())))
});

MODIFY
crates/rome_lsp/src/session.rs
crates/rome_lsp/src/session.rs
@@ -15,6 +15,7 @@ use rome_service::workspace::{RageEntry, RageParams, RageResult, UpdateSettingsP
use rome_service::{load_config, Workspace};
use rome_service::{DynRef, RomeError};
use std::collections::HashMap;
+use std::path::PathBuf;
use std::sync::RwLock;
use std::sync::{Arc, Mutex};
use tokio::sync::Notify;
@@ -196,16 +197,20 @@ impl Session {
== Some(true)
}
- /// This function attempts to read the configuration from the root URI
- pub(crate) async fn update_configuration(&self) {
+ pub(crate) fn base_path(&self) -> Option<PathBuf> {
let root_uri = self.root_uri.read().unwrap();
- let base_path = root_uri.as_ref().and_then(|root_uri| match root_uri.to_file_path() {
+ root_uri.as_ref().and_then(|root_uri| match root_uri.to_file_path() {
Ok(base_path) => Some(base_path),
Err(()) => {
error!("The Workspace root URI {root_uri:?} could not be parsed as a filesystem path");
None
}
- });
+ })
+ }
+
+ /// This function attempts to read the configuration from the root URI
+ pub(crate) async fn update_configuration(&self) {
+ let base_path = self.base_path();
match load_config(&self.fs, base_path) {
Ok(Some(configuration)) => {
@@ -241,6 +246,19 @@ impl Session {
error!("Cannot set workspace settings: {}", err);
})
.ok()?;
+ self.update_workspace_settings();
+
+ Some(())
+ });
+ } else {
+ trace!("Cannot read configuration from the client");
+ }
+ }
+
+ /// If updates the [Workspace] settings with the new configuration that was
+ /// read from file.
+ #[tracing::instrument(level = "debug", skip(self))]
+ pub(crate) fn update_workspace_settings(&self) {
let mut configuration = self.configuration.write().unwrap();
// This operation is intended, we want to consume the configuration because once it's read
@@ -259,12 +277,6 @@ impl Session {
error!("{:?}", &error)
}
}
-
- Some(())
- });
- } else {
- trace!("Cannot read configuration from the client");
- }
}
/// Broadcast a shutdown signal to all active connections

MODIFY
crates/rome_service/Cargo.toml
crates/rome_service/Cargo.toml
@@ -27,7 +27,7 @@ rome_rowan = { path = "../rome_rowan", features = ["serde"] }
rome_text_edit = { path = "../rome_text_edit" }
indexmap = { workspace = true, features = ["serde"] }
schemars = { version = "0.8.10", features = ["indexmap1"], optional = true }
-tracing = { workspace = true }
+tracing = { workspace = true, features = ["attributes"] }
[features]
schemars = ["dep:schemars", "rome_formatter/serde", "rome_js_factory", "rome_text_edit/schemars"]

MODIFY
crates/rome_service/src/file_handlers/javascript.rs
crates/rome_service/src/file_handlers/javascript.rs
@@ -34,6 +34,7 @@ use rome_diagnostics::{v2, v2::Diagnostic};
use rome_js_analyze::utils::rename::{RenameError, RenameSymbolExtensions};
use std::borrow::Cow;
use std::fmt::Debug;
+use tracing::debug;
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
@@ -425,6 +426,7 @@ fn fix_all(params: FixAllParams) -> Result<FixFileResult, RomeError> {
}
}
+#[tracing::instrument(level = "debug", skip(parse))]
fn format(
rome_path: &RomePath,
parse: AnyParse,
@@ -432,6 +434,8 @@ fn format(
) -> Result<Printed, RomeError> {
let options = settings.format_options::<JsLanguage>(rome_path);
+ debug!("Format with the following options: \n{}", options);
+
let tree = parse.syntax();
let formatted = format_node(options, &tree)?;

MODIFY
crates/rome_service/src/settings.rs
crates/rome_service/src/settings.rs
@@ -36,6 +36,7 @@ impl WorkspaceSettings {
}
/// The (configuration)[Configuration] is merged into the workspace
+ #[tracing::instrument(level = "debug", skip(self))]
pub fn merge_with_configuration(
&mut self,
configuration: Configuration,

MODIFY
crates/rome_service/src/workspace/server.rs
crates/rome_service/src/workspace/server.rs
@@ -261,6 +261,7 @@ impl Workspace for WorkspaceServer {
/// ## Panics
/// This function may panic if the internal settings mutex has been poisoned
/// by another thread having previously panicked while holding the lock
+ #[tracing::instrument(level = "debug", skip(self))]
fn update_settings(&self, params: UpdateSettingsParams) -> Result<(), RomeError> {
let mut settings = self.settings.write().unwrap();
settings.merge_with_configuration(params.configuration)?;

MODIFY
editors/vscode/README.md
editors/vscode/README.md
Adds support for the Rome language server to provide formatting, diagnostics, and code actions.
+## How the extension works
+
+The extension acts as a language server, which means that you will get all the features
+provided by the extension (formatting, diagnostics, etc.) for any file supported by Rome.
+
+The extension automatically discovers the `rome.json` file in the workspace root directory.
+
+## Known limitations
+
+There are a few limitations that the team plans to remove in the following releases.
+
+- the discovery of the `rome.json` is limited to the root of the workspace
+- changes to the configuration `rome.json` won't be picked automatically; use the VSCode command
+ `Restart LSP Server` or use `rome stop` command;
+- when updating `rome` inside you `package.json`, the rome server needs to be restarted;
+ you can use `rome stop` command or kill the process manually;
+- if you don't want to see Rome's diagnostics in projects that don't use Rome, you need to disable
+ the extension;
+
+## Supported languages
+
+Check the [website](https://rome.tools/#language-support) for more information.
+
## Usage
This extension may be bundled with a prebuilt binary for `rome_lsp`, the Rome language server.

MODIFY
editors/vscode/package-lock.json
editors/vscode/package-lock.json
"@types/node": "^18.0.0",
"@types/vscode": "^1.70.0",
"esbuild": "^0.14.47",
- "rome": "next",
"typescript": "^4.8.2",
"vsce": "^2.11.0",
"vscode-languageclient": "^8.0.2"
"vscode": "^1.70.0"
}
},
- "node_modules/@rometools/cli-darwin-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-arm64/-/cli-darwin-arm64-0.7.0-next.tgz",
- "integrity": "sha512-GMHYG5zQTGerQYue30m/E+WgpoPCxjLT7unCF1BH0jgFSk/fgkduMY9QP9EetNuBYxP/03XFZgXIZLmyw+Shgw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rometools/cli-darwin-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-x64/-/cli-darwin-x64-0.7.0-next.tgz",
- "integrity": "sha512-MyM/ncZKs3mIJ0vsSNyGNKGR31VroK2W7mHqPRVyuVkrmaJnDko8ymzH/JSrBdD7hj8KU3Ubpjn8YNuaMZvSYQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rometools/cli-linux-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-linux-arm64/-/cli-linux-arm64-0.7.0-next.tgz",
- "integrity": "sha512-X3gCoT3GDioVkHsOfthMEoa1BR8lx1eXi7Sn0SeoHpw04UF+4WIn9Rjb62Fx/lIvRIdtxVj74pz14dxVQ/8HkQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rometools/cli-linux-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-linux-x64/-/cli-linux-x64-0.7.0-next.tgz",
- "integrity": "sha512-3kpV+cs2MgqUk8gjM1nPXmAoXErDGLEaK/q60c5FkNZQfuKxp6lN5sGF8cxJLbxggOaWXGfiIRoS9BBp9YIbEw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rometools/cli-win32-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-win32-arm64/-/cli-win32-arm64-0.7.0-next.tgz",
- "integrity": "sha512-mOSg9CAeYgjK6W8e13epaOFeHPITvhAIj7wib8N8KtW8Mi8LgSdNCg3Pr1zRcN2F4ndDNfGZYiDf9A0Xl2N/Zw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rometools/cli-win32-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-win32-x64/-/cli-win32-x64-0.7.0-next.tgz",
- "integrity": "sha512-JrsHY4IXd3SSF3TXwP15PloVXGR5A1or7yV9gFyrmmRVsyFpJYkAh4oU4IuAoqltPi9G4c3oEEQhN8yzYoUwKw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
"node_modules/@types/node": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz",
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/rome": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/rome/-/rome-0.7.0-next.tgz",
- "integrity": "sha512-bbzyM95xMGzFCn+74tXyFJ39RGifEbGYFz0bB+SRtPSx0DZfpkHjcmqX9UiuMtWAkdQnWFG2rsrivQnDqqxTPA==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "rome": "bin/rome"
- },
- "engines": {
- "node": ">=14.18.0"
- },
- "optionalDependencies": {
- "@rometools/cli-darwin-arm64": "0.7.0-next",
- "@rometools/cli-darwin-x64": "0.7.0-next",
- "@rometools/cli-linux-arm64": "0.7.0-next",
- "@rometools/cli-linux-x64": "0.7.0-next",
- "@rometools/cli-win32-arm64": "0.7.0-next",
- "@rometools/cli-win32-x64": "0.7.0-next"
- }
- },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
}
},
"dependencies": {
- "@rometools/cli-darwin-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-arm64/-/cli-darwin-arm64-0.7.0-next.tgz",
- "integrity": "sha512-GMHYG5zQTGerQYue30m/E+WgpoPCxjLT7unCF1BH0jgFSk/fgkduMY9QP9EetNuBYxP/03XFZgXIZLmyw+Shgw==",
- "dev": true,
- "optional": true
- },
- "@rometools/cli-darwin-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-x64/-/cli-darwin-x64-0.7.0-next.tgz",
- "integrity": "sha512-MyM/ncZKs3mIJ0vsSNyGNKGR31VroK2W7mHqPRVyuVkrmaJnDko8ymzH/JSrBdD7hj8KU3Ubpjn8YNuaMZvSYQ==",
- "dev": true,
- "optional": true
- },
- "@rometools/cli-linux-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-linux-arm64/-/cli-linux-arm64-0.7.0-next.tgz",
- "integrity": "sha512-X3gCoT3GDioVkHsOfthMEoa1BR8lx1eXi7Sn0SeoHpw04UF+4WIn9Rjb62Fx/lIvRIdtxVj74pz14dxVQ/8HkQ==",
- "dev": true,
- "optional": true
- },
- "@rometools/cli-linux-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-linux-x64/-/cli-linux-x64-0.7.0-next.tgz",
- "integrity": "sha512-3kpV+cs2MgqUk8gjM1nPXmAoXErDGLEaK/q60c5FkNZQfuKxp6lN5sGF8cxJLbxggOaWXGfiIRoS9BBp9YIbEw==",
- "dev": true,
- "optional": true
- },
- "@rometools/cli-win32-arm64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-win32-arm64/-/cli-win32-arm64-0.7.0-next.tgz",
- "integrity": "sha512-mOSg9CAeYgjK6W8e13epaOFeHPITvhAIj7wib8N8KtW8Mi8LgSdNCg3Pr1zRcN2F4ndDNfGZYiDf9A0Xl2N/Zw==",
- "dev": true,
- "optional": true
- },
- "@rometools/cli-win32-x64": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/@rometools/cli-win32-x64/-/cli-win32-x64-0.7.0-next.tgz",
- "integrity": "sha512-JrsHY4IXd3SSF3TXwP15PloVXGR5A1or7yV9gFyrmmRVsyFpJYkAh4oU4IuAoqltPi9G4c3oEEQhN8yzYoUwKw==",
- "dev": true,
- "optional": true
- },
"@types/node": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz",
"glob": "^7.1.3"
}
},
- "rome": {
- "version": "0.7.0-next",
- "resolved": "https://registry.npmjs.org/rome/-/rome-0.7.0-next.tgz",
- "integrity": "sha512-bbzyM95xMGzFCn+74tXyFJ39RGifEbGYFz0bB+SRtPSx0DZfpkHjcmqX9UiuMtWAkdQnWFG2rsrivQnDqqxTPA==",
- "dev": true,
- "requires": {
- "@rometools/cli-darwin-arm64": "0.7.0-next",
- "@rometools/cli-darwin-x64": "0.7.0-next",
- "@rometools/cli-linux-arm64": "0.7.0-next",
- "@rometools/cli-linux-x64": "0.7.0-next",
- "@rometools/cli-win32-arm64": "0.7.0-next",
- "@rometools/cli-win32-x64": "0.7.0-next"
- }
- },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",

MODIFY
editors/vscode/package.json
editors/vscode/package.json
"package": "vsce package -o rome_lsp.vsix",
"build": "npm run compile -- --minify && npm run package",
"install-extension": "code --install-extension rome_lsp.vsix --force",
- "format": "cargo run --bin rome format ./src/ ./scripts --write",
+ "format": "cargo rome-cli-dev format ./src/ ./scripts --write",
+ "check": "cargo rome-cli-dev check ./src/ ./scripts",
"pack:dev": "npm run compile && npm run package && npm run install-extension",
"tsc": "tsc"
},
"typescript": "^4.8.2",
"vsce": "^2.11.0",
"esbuild": "^0.14.47",
- "rome": "next",
"vscode-languageclient": "^8.0.2"
}
}

MODIFY
editors/vscode/src/lsp_requests.ts
editors/vscode/src/lsp_requests.ts
@@ -12,3 +12,16 @@ export const syntaxTreeRequest = new RequestType<
string,
void
>("rome_lsp/syntaxTree");
+
+// Empty parameters
+export interface UpdateSettingsParams {
+ configuration: any;
+}
+/**
+ * Request to send to the server when the configuration file changed
+ */
+export const updateSettingsRequest = new RequestType<
+ UpdateSettingsParams,
+ string,
+ void
+>("rome/update_settings");

MODIFY
editors/vscode/src/main.ts
editors/vscode/src/main.ts
@@ -15,13 +15,14 @@ import {
ServerOptions,
StreamInfo,
} from "vscode-languageclient/node";
-import { join, isAbsolute } from "path";
-import { existsSync } from "fs";
+import { isAbsolute, join } from "path";
+import { existsSync, readFileSync } from "fs";
import { setContextValue } from "./utils";
import { Session } from "./session";
import { syntaxTree } from "./commands/syntaxTree";
import { Commands } from "./commands";
import { StatusBar } from "./statusBar";
+import { updateSettingsRequest } from "./lsp_requests";
let client: LanguageClient;
@@ -107,7 +108,6 @@ export async function activate(context: ExtensionContext) {
);
handleActiveTextEditorChanged(window.activeTextEditor);
-
client.start();
}

feat(vscode): watch configuration file (#3284)